Skip to main content

Transform owned collections in place

When you hold a mutable reference to an owned value, such as a Vec, some complex operations are impossible because they would require taking ownership of the value. The take_mut::take function solves this by temporarily moving the value out of the reference, allowing you to transform it in a closure, and then placing the returned value back into the original reference.

For example, if you need to sort and deduplicate a vector in-place, you can use take to gain ownership within a closure, perform the operations, and return the modified vector.

fn main() {
use take_mut::take;

let mut values = vec![3, 1, 4, 1, 5, 9, 2, 6];

take(&mut values, |mut v| {
v.sort();
v.dedup();
v
});

assert_eq!(values, vec![1, 2, 3, 4, 5, 6, 9]);
}

The function is generic and works with any type. You can perform different kinds of transformations, like reversing a vector of strings and extending it with new elements. The closure takes the original Vec<String>, reverses it, appends more strings, and returns the final vector which then replaces the original.

fn main() {
use take_mut::take;

let mut words = vec!["hello".to_string(), "world".to_string()];

take(&mut words, |mut w| {
w.reverse();
w.extend(vec!["new".to_string(), "words".to_string()]);
w
});

assert_eq!(words, vec!["world".to_string(), "hello".to_string(), "new".to_string(), "words".to_string()]);
}

It is important to understand that take_mut::take provides a critical safety guarantee. If the closure you provide panics, the original value has already been moved and there is no new value to replace it. To prevent the mutable reference from being left in an invalid, uninitialized state, the process will abort. This is a deliberate design choice to ensure memory safety. Unlike std::mem::replace, you don't need to provide a replacement value upfront; you generate it from the old value inside the closure.