Example scenario
struct Foo {
bar: Vec<i32>,
}
let foo = Foo { bar: vec![1, 2, 3] };
let bar: HashMap<i32, i32> = foo.bar.into_iter().map(|x|(x,x)).collect();
Expected behaviour: all values from foo.bar moved into new hash map, foo.bar now is clean vec and can be used after this, foo as whole struct can be used after this.
Real behaviour: foo.bar moved as whole collection, so whole struct foo now is partial moved and cant be used.
Question: why into_iter consume whole collection instead of consuming only elements and leave struct empty and how I can workaround this ?
>Solution :
Why calling
into_iteronVec<T>consumes vector?
This is because IntoIterator trait is defined to consume value turned into iterator (by convention "into" in Rust means that you change something into something else, if you only want to view/borrow something, usually you will see "as"; for example Vec::as_slice).
pub trait IntoIterator {
type Item;
type IntoIter: Iterator<Item = Self::Item>;
// Required method
fn into_iter(self) -> Self::IntoIter;
}
Vec::into_iter essentially uses this trait, so it only makes sense that it consumes vector.
How to "take" some value and leave an empty value in its place to avoid partial move?
You can use std::mem::take, which is defined as:
pub fn take<T>(dest: &mut T) -> T
where
T: Default,
It takes value from &mut T and uses trait Default to construct a default (usually empty in case of collections) object in its place. Since Vec implements Default you can use it as follows:
struct Foo {
bar: Vec<i32>,
}
fn main() {
let mut foo = Foo { bar: vec![1, 2, 3] };
// Take foo.bar so it can be consumed later, and leave an empty vector in its place.
// Note that this requires mutating foo.
let bar = std::mem::take(&mut foo.bar);
let bar: std::collections::HashMap<i32, i32> = bar.into_iter().map(|x| (x, x)).collect();
println!("{bar:?}");
}
In general if you want to take some value, which does not implement Default trait, or you want to use different value than it provides, you can use std::mem::replace or std::mem::swap.