Getting value from a collection without using the Clone trait - rust

Is it possible to get a value from a collection and apply a method to it which accepts only self and not &self?
Minimal Working Example
What I would like to write is something akin to:
use std::collections::HashMap;
fn get<B>(key: i32, h: HashMap<i32, Vec<(i32, B)>>) -> i32 where B: Into<i32> {
let v: &Vec<(i32, B)> = h.get(&key).unwrap();
let val: &B = v.first().unwrap().1;
// Do something to be able to call into
// I only need the value as read-only
// Does B have to implement the Clone trait?
return val.into();
}
I have tried in vain to dribble mut here and there to try to appease compiler error after compiler error, but this is really a fool's errand.
use std::collections::HashMap;
fn get<B>(key: i32, mut h: HashMap<i32, Vec<(i32, B)>>) -> i32 where B: Into<i32> {
let mut v: &Vec<(i32, B)> = h.get_mut(&key).unwrap();
let ref mut val: B = v.first_mut().unwrap().1;
return (*val).into();
}
Is this sort of thing even possible or does B have to implement the Clone trait?
I've also tried:
Unsafe
Raw pointers
I've not tried:
Box
Other Rust constructs that I have not encountered,
I mention this to explicitly state that I have not
omitted any approaches that I know of.

Is it possible to get a value from a collection and apply a method to it which accepts only self and not &self?
In general, no, not without removing it from the collection. The collection owns the value. Methods that take self want to transform the item while consuming the ownership, so you have to transfer ownership.
Cloning or copying an item creates a new item with new ownership that you can then give to the method.
In your particular case, you can almost get away with this exciting where clause:
where for<'a> &'a B: Into<i32>
Except From<&i32> is not implemented for i32. You can write a trait that does what you want though:
use std::collections::HashMap;
trait RefInto<T> {
fn into(&self) -> T;
}
impl RefInto<i32> for i32 {
fn into(&self) -> i32 { *self }
}
fn get<B>(key: i32, h: HashMap<i32, Vec<(i32, B)>>) -> i32
where B: RefInto<i32>
{
let v = h.get(&key).unwrap();
let val = &v.first().unwrap().1;
val.into()
}
// ----
fn main() {
let mut map = HashMap::new();
map.insert(42, vec![(100, 200)]);
let v = get(42, map);
println!("{:?}", v);
}
Alternatively, you might be able to make use of Borrow:
use std::collections::HashMap;
use std::borrow::Borrow;
fn get<B>(key: i32, h: HashMap<i32, Vec<(i32, B)>>) -> i32
where B: Borrow<i32>
{
let v = h.get(&key).unwrap();
let val = &v.first().unwrap().1;
*val.borrow()
}

The function consumes the HashMap. I'm assuming this is your intent and that you therefore don't care about any of its content except the one element you wish to convert into an i32.
You can use the HashMap::remove method to extract a value. You can then use Vec::swap_remove to extract the first element.
use std::collections::HashMap;
fn get<B>(key: i32, mut h: HashMap<i32, Vec<(i32, B)>>) -> i32 where B: Into<i32> {
h.remove(&key)
.unwrap()
.swap_remove(0)
.1
.into()
}
If B is cheap to copy, then it makes more sense to write a function where it is copied.
The above doesn't handle errors. A version with error handling could look like this:
use std::collections::HashMap;
fn get<B>(key: i32, mut h: HashMap<i32, Vec<(i32, B)>>) -> Option<i32> where B: Into<i32> {
h.remove(&key)
.and_then(|mut vec| {
if vec.is_empty() { None }
else { Some(vec.swap_remove(0).1.into()) }
})
}
Vec::swap_remove isn't ideal. The functionality of moving an element at an arbitrary index out of the vector without any other work would be handled by the IndexMove trait which doesn't yet exist though.

Related

Efficient Rust collector of Results holding Vecs

I'm learning Rust, and I've come upon the following pattern which collapses an iterator of Result<Vec<_>, _>s to a single big Vec<_>, failing if any of the results from the iterator failed:
fn accumulate<T, E>(it: impl Iterator<Item = Result<Vec<T>, E>>) -> Result<Vec<T>, E> {
let mut result = Vec::new();
for mut ts in it {
result.append(&mut ts?)
}
Ok(result)
}
I assume a very short "functional-style" version of this function can be written, and I'm struggling to find it. Morally, I'd like to do something like
it.map(|v| v?.into_iter()).flatten().collect()
but this doesn't typecheck. By running small examples, I think the point of the flatten there is to silently drop error results, but I'd instead like to somehow "map the flatten under the Results". I know also that in general you couldn't collect, say, an iterator of type
impl Iterator<Item = Result<impl Iterator<Item = T>, Error>>
into an iterator
Result<impl Iterator<Item = impl Iterator<Item = T>>, Error>
since you need to have actually done all of the computations in the outer iterator in order to know the final result. Nonetheless, it seems that you can make this work in this special case, when you want to .flatten() and then .collect() right after.
Finally, I can see that that collect() gives me a way to build a vector of vectors from it, and then I could flatten this vector into the single big vector I want. But this has many needless memory allocations.
Can the standard library help you do this in an efficient, Rust-ic way?
I think I would start with try_fold, as it can deal with Result and stop on Err:
fn acc2<T, E>(mut it: impl Iterator<Item = Result<Vec<T>, E>>) -> Result<Vec<T>, E> {
it.try_fold(
Vec::new(),
|mut vec, res_ts: Result<Vec<_>, E>| {
res_ts.map(move |mut ts| { // map preserves Err
// In case of Ok(...), append to already found elements
vec.append(&mut ts);
vec
})
}
)
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f6f738ddedecda1875df283f221dbfdc
It turns out, Itertools already has fold_results that should do what you want:
fn acc3<T, E>(mut it: impl Iterator<Item = Result<Vec<T>, E>>) -> Result<Vec<T>, E> {
it.fold_results(
Vec::new(),
|mut vec, mut ts| {
vec.append(&mut ts);
vec
}
)
}
To achieve this only using iterator methods:
use std::iter::{self, Iterator};
pub fn accumulate<T, E>(it: impl Iterator<Item = Result<Vec<T>, E>>) -> Result<Vec<T>, E> {
it.flat_map(|v| {
v.map_or_else(
|e| Iter::A(iter::once(Err(e))),
|t| Iter::B(t.into_iter().map(Ok)),
)
})
.collect()
}
// Utility enum that can be generated by the #[auto_enum] derive macro
enum Iter<T, A: Iterator<Item = T>, B: Iterator<Item = T>> {
A(A),
B(B),
}
impl<T, A: Iterator<Item = T>, B: Iterator<Item = T>> Iterator for Iter<T, A, B> {
type Item = T;
fn next(&mut self) -> Option<T> {
match self {
Self::A(a) => a.next(),
Self::B(b) => b.next(),
}
}
}
This uses flat_map to yield either an iterator of Oks or an iterator of an Err for each entry.
This is semantically equivalent to your control flow code using for loop.
Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=68558e27900940476e443d670a120e91
See auto_enums for deriving an enum delegating Iterator variants.
Alternatively, you can use either::Either in place of Iter, which has the same implementation for two items:
https://docs.rs/either/1.5.3/either/enum.Either.html#impl-Iterator

Is it possible to create a wrapper around an &mut that acts like an &mut

The following code fails to compile because MutRef is not Copy. It can not be made copy because &'a mut i32 is not Copy. Is there any way give MutRef similar semantics to &'a mut i32?
The motivation for this is being able to package up a large set of function parameters into a struct so that they can be passed as a group instead of needing to be passed individually.
struct MutRef<'a> {
v: &'a mut i32
}
fn wrapper_use(s: MutRef) {
}
fn raw_use(s: &mut i32) {
}
fn raw_ref() {
let mut s: i32 = 9;
let q = &mut s;
raw_use(q);
raw_use(q);
}
fn wrapper() {
let mut s: i32 = 9;
let q = MutRef{ v: &mut s };
wrapper_use(q);
wrapper_use(q);
}
No.
The name for this feature is "implicit reborrowing" and it happens when you pass a &mut reference where the compiler expects a &mut reference of a possibly different lifetime. The compiler only implicitly reborrows when the actual type and the expected type are both &mut references. It does not work with generic arguments or structs that contain &mut references. There is no way in current Rust to make a custom type that can be implicitly reborrowed. There is an open issue about this limitation dating from 2015, but so far nobody has proposed any way to lift it.
You can always implement your own method to explicitly reborrow:
impl<'a> MutRef<'a> {
// equivalent to fn reborrow(&mut self) -> MutRef<'_>
fn reborrow<'b>(&'b mut self) -> MutRef<'b> {
MutRef {v: self.v}
}
}
fn wrapper() {
let mut s: i32 = 9;
let mut q = MutRef{ v: &mut s };
wrapper_use(q.reborrow()); // does not move q
wrapper_use(q); // moves q
}
See also
Why is the mutable reference not moved here?
Type inference and borrowing vs ownership transfer

Move a variable that is owned by &mut self to another thread without cloning/copying [duplicate]

I have a struct with a field:
struct A {
field: SomeType,
}
Given a &mut A, how can I move the value of field and swap in a new value?
fn foo(a: &mut A) {
let mut my_local_var = a.field;
a.field = SomeType::new();
// ...
// do things with my_local_var
// some operations may modify the NEW field's value as well.
}
The end goal would be the equivalent of a get_and_set() operation. I'm not worried about concurrency in this case.
Use std::mem::swap().
fn foo(a: &mut A) {
let mut my_local_var = SomeType::new();
mem::swap(&mut a.field, &mut my_local_var);
}
Or std::mem::replace().
fn foo(a: &mut A) {
let mut my_local_var = mem::replace(&mut a.field, SomeType::new());
}
If your type implements Default, you can use std::mem::take:
#[derive(Default)]
struct SomeType;
fn foo(a: &mut A) {
let mut my_local_var = std::mem::take(&mut a.field);
}
If your field happens to be an Option, there's a specific method you can use — Option::take:
struct A {
field: Option<SomeType>,
}
fn foo(a: &mut A) {
let old = a.field.take();
// a.field is now None, old is whatever a.field used to be
}
The implementation of Option::take uses mem::take, just like the more generic answer above shows, but it is wrapped up nicely for you:
pub fn take(&mut self) -> Option<T> {
mem::take(self)
}
See also:
Temporarily move out of borrowed content
Change enum variant while moving the field to the new variant

Is it possible to pass an object method as argument to a function and bind it to the object?

Is it possible to make a bind to object method? For example, I have a vector and a lot of functions which do something if some item exists in the vector. I would implement it as follows:
fn perform_if_exists(item: u8, vector: &Vec<u8>, func: fn(usize)) {
let idx = vector.iter().position(|i| *i == item );
match idx {
Some(i) => func(i),
None => {},
}
}
fn main() {
let v: Vec<u8> = vec![1, 2, 3];
perform_if_exists(1, &v, Vec<_>::remove);
}
but it gives a lot of errors. I think they are reasonable but it's because I don't understand how to put vector's method as argument to a function.
Is it possible
Sure it is. You have to fix the multiple cascading errors first:
Invalid syntax: Vec<_>::remove isn't valid.
Incompatible argument types: Vec::remove modifies a Vec, so you have to pass in a Vec somehow.
Mutability: Vec::remove modifies a Vec, so you have to declare that the function is allowed to do so.
Vec::remove returns the removed value, so you have to allow the function to return a value, even if it's thrown away.
fn perform_if_exists<F, R>(item: u8, vector: &mut Vec<u8>, func: F)
where
F: Fn(&mut Vec<u8>, usize) -> R,
{
let idx = vector.iter().position(|i| *i == item);
if let Some(i) = idx {
func(vector, i);
}
}
fn main() {
let mut v = vec![1, 2, 3];
perform_if_exists(1, &mut v, Vec::remove);
println!("{:?}", v);
}
I switched to a generic as that's generally how you will accept closures. A function pointer is fine but more restrictive.
A method in Rust is nothing more than a function, which also takes a first self parameter. The method Vec::remove takes two arguments: &mut self and index: usize. The self parameter is always of type Self, which is Vec<u8> in this case. The complete type of Vec::<u8>::remove is: fn(&mut Vec<u8>, usize) -> u8 (yes it also returns the removed element).
After changing the type in your code (+ a few minor mistakes), it works:
// vvv-- has to be mutable
fn perform_if_exists(item: u8, vector: &mut Vec<u8>, func: fn(&mut Vec<u8>, usize) -> u8) {
let idx = vector.iter().position(|i| *i == item );
match idx {
Some(i) => {
func(vector, i);
},
None => {},
}
}
fn main() {
let mut v: Vec<u8> = vec![1, 2, 3];
perform_if_exists(1, &mut v, Vec::remove);
}
But fn(...) -> ... types are raw pointer types and just work for ordinary functions. Often you also want to enable the user to pass anything that is "callable", like closures. There are traits exactly for that purpose: Fn(...) -> ....
Let me propose another solution:
fn perform_if_exists<T, F, R>(item: T, vector: &mut Vec<T>, func: F) -> Option<R>
where F: FnOnce(&mut Vec<T>, usize) -> R,
T: PartialEq
{
let idx = vector.iter().position(|i| *i == item );
idx.map(|i| func(vector, i))
}
This solution is far more generic as it allows arbitrary item types, arbitrary "callable" types and returns the value that is returned by the given function. Note that the main function didn't change; the solution is more generic, but all old uses still work.

How to write a safe wrap for HashMap with default value

I implemented a wrap for HashMap with default values and I would like to know if it's safe.
When get is called, the internal map may be resized and previous references to values (obtained with get) would be pointing to invalid address. I tried to solve this problem using the idea that "all problems in computer science can be solved by another level of indirection" (Butler Lampson). I would like to know if this trick makes this code safe.
use std::cell::UnsafeCell;
use std::collections::HashMap;
use std::hash::Hash;
pub struct DefaultHashMap<I: Hash + Eq, T: Clone> {
default: T,
map: UnsafeCell<HashMap<I, Box<T>>>,
}
impl<I: Hash + Eq, T: Clone> DefaultHashMap<I, T> {
pub fn new(default: T) -> Self {
DefaultHashMap {
default: default,
map: UnsafeCell::new(HashMap::new()),
}
}
pub fn get_mut(&mut self, v: I) -> &mut T {
let m = unsafe { &mut *self.map.get() };
m.entry(v).or_insert_with(|| Box::new(self.default.clone()))
}
pub fn get(&self, v: I) -> &T {
let m = unsafe { &mut *self.map.get() };
m.entry(v).or_insert_with(|| Box::new(self.default.clone()))
}
}
#[test]
fn test() {
let mut m = DefaultHashMap::new(10usize);
*m.get_mut(4) = 40;
let a = m.get(4);
for i in 1..1024 {
m.get(i);
}
assert_eq!(a, m.get(4));
assert_eq!(40, *m.get(4));
}
(Playground)
Since you cannot1 mutate the value returned from get, I'd just return a reference to the default value when the value is missing. When you call get_mut however, you can then add the value to the map and return the reference to the newly-added value.
This has the nice benefit of not needing any unsafe code.
use std::{borrow::Borrow, collections::HashMap, hash::Hash};
pub struct DefaultHashMap<K, V> {
default: V,
map: HashMap<K, V>,
}
impl<K, V> DefaultHashMap<K, V>
where
K: Hash + Eq,
V: Clone,
{
pub fn new(default: V) -> Self {
DefaultHashMap {
default,
map: HashMap::new(),
}
}
pub fn get_mut(&mut self, v: K) -> &mut V {
let def = &self.default;
self.map.entry(v).or_insert_with(|| def.clone())
}
pub fn get<B>(&self, v: B) -> &V
where
B: Borrow<K>,
{
self.map.get(v.borrow()).unwrap_or(&self.default)
}
}
#[test]
fn test() {
let mut m = DefaultHashMap::new(10usize);
*m.get_mut(4) = 40;
let a = m.get(4);
for i in 1..1024 {
m.get(i);
}
assert_eq!(a, m.get(4));
assert_eq!(40, *m.get(4));
}
[1]: Technically this will have different behavior if your default value contains internal mutability. In that case, modifications to the default value would apply across the collection. If that's a concern, you'd need to use a solution closer to your original.
I think that you are covered by the borrowing rules here.
Applying the Mutability XOR Aliasing principle here, unsafety would crop up if you could maintain multiple paths to the same value and mutate something at the same time.
In your case, however:
while the internal HashMap can be mutated even through an aliasable reference to DefaultHashMap, nobody has a reference into the HashMap itself
while there are references into the Box, there is no possibility here to erase a Box, so no dangling pointer from here
since you take care to preserve the borrowing relationship (ie, &mut T is only obtained through a &mut DefaultHashMap), it is not possible to have a &mut T and an alias into it
So, your short example looks safe, however be especially wary of not accidentally introducing a method on &DefaultHashMap which would allow to modify an existing value as this would be a short road to dangling pointers.
Personally, I would execute all tests with an Option<String>.

Resources