This is a nice pattern that takes the idea of Option::take and extends it to Vec.
/// Replace the value with an "empty" state and return the original value
trait Take {
fn take(&mut self) -> Self;
}
impl<T> Take for Vec<T> {
fn take(&mut self) -> Self {
::std::mem::replace(self, Vec::new())
}
}
This is nice because it allows writing code that replaces a vector with a map of it (playground)
Edited to actually use ownership semantics, where this matters: A vec of Strings for example.
This is a trait for C++ style non-destructive move semantics! It would be nice to have such trait in libstd.
There are plenty of types that can implement it.
trait Yoink {
/**
Yoinks the current value out from under the owner's feet, replacing it with
the default value... hopefully before anyone notices.
*/
fn yoink(&mut self) -> Self;
}
impl<T> Yoink for T where T: Default {
fn yoink(&mut self) -> Self {
::std::mem::replace(self, Self::default())
}
}
Itās sad, but your name is better (HashSet is already using .take() for a different purpose). The nice thing about a less spray-y version is that Vecās implementation is totally cheap and appropriate for the kind of replace-map-assign transformation, while most other collections are not that nice.
For name-bikeshedding, I suggest Default::replace_default(&mut self) ā implemented with mem::replace as suggested, but of course that can be overridden if any type wants for some reason.
While I agree, I think a more functional approach like in-place mapping or retain_mut as you mentioned would be clearer and easier to use. I know at least that I would rather use a higher order function that did everything in place than think about move/copy semantics. Speaking of which, is this code equivalent to your example or is it less efficient?
Itās less efficient since .into_iter() on a &mut Vec gives you the same as iter_mut(), so x is a &mut String. Since the string is taken by reference, a full copy of each string is forced, and thatās the overhead.