Skip to main content

Transform owned collections in place

The take_mut::take function allows you to perform complex transformations on a value behind a mutable reference by temporarily taking ownership of it. While standard Rust borrowing rules often require you to work with references, take_mut enables scenarios where you need to consume the original value or perform operations that are only possible with an owned instance, such as certain collection manipulations.

When you have a Vec and need to perform a sequence of operations that require ownership—like sorting and deduplicating—you can use take_mut::take to move the vector into a closure, modify it, and return it to the original location.

fn main() {
use take_mut::take;

let mut v = vec![1, 5, 3, 2, 5, 2, 4];

// Use take to sort and deduplicate the vector in place
take(&mut v, |mut v| {
v.sort();
v.dedup();
v
});

assert_eq!(v, vec![1, 2, 3, 4, 5]);
}

Internally, take_mut::take uses std::ptr::read to move the value out of the mutable reference and std::ptr::write to put the result of the closure back. This mechanism is designed to be safe as long as the closure returns a valid value of the same type. However, because the memory location is temporarily invalid while the closure is running, take_mut will exit the program if the closure panics to prevent access to uninitialized memory.

You can also use this pattern to perform structural changes, such as reversing a collection and extending it with new elements. This is useful when the new elements are provided as an owned collection that you want to merge into the existing one after a transformation.

fn main() {
use take_mut::take;

let mut v = vec!['a', 'b', 'c'];

// Use take to reverse the vector and extend it with new elements
take(&mut v, |mut v| {
v.reverse();
v.extend(vec!['d', 'e']);
v
});

assert_eq!(v, vec!['c', 'b', 'a', 'd', 'e']);
}