Is it possible to write a function which modifies a struct
member in place such that one can use it with both Vec
and HashMap::values()
?
This is what I came up so far:
use std::collections::HashMap;
struct Foo {
x: i32,
}
fn process_collection<T>(collection: &mut T)
where
T: IntoIterator<Item = Foo>,
for<'a> &'a mut T: IntoIterator<Item = &'a mut Foo>,
{
for item in collection.into_iter() {
item.x = 5;
}
}
fn main() {
let mut numbers = vec![Foo { x: 1 }, Foo { x: 2 }];
// Set all .x members to 5.
process_collection(&mut numbers);
for item in &numbers {
println!("item after: {}", item.x);
}
let mut data: HashMap<String, Foo> = HashMap::new();
data.insert("One".to_string(), Foo {x: 1} );
data.insert("Two".to_string(), Foo {x: 2});
// This does not compile.
process_collection(&mut data.values());
}
To modify the elements in place, you only need an iterator with mutable access:
fn process_collection<'a, T>(collection: T)
where
T: IntoIterator<Item = &'a mut Foo>,
{
for item in collection {
item.x = 5;
}
}
With which you can call with a Vec<Foo>
like this:
process_collection(&mut numbers);
Or with the values from a HashMap<_, Foo>
like this:
process_collection(data.values_mut());
Note the changes:
T: IntoIterator
and &mut T: IntoIterator
. Though collections often have both implementations, that is not needed and wouldn't work for the values of a HashMap
.values_mut()
instead of just values()
since the latter only provides immutable references.collection
is passed as an owned value and not as a mutable reference since it is more idiomatic.