Skip to main content

Transform owned collections in place

The take_mut::take function allows you to transform an owned value in place when you only have a mutable reference to it. In standard Rust, you cannot move a value out of a mutable reference because the reference must always point to a valid instance of the type. While std::mem::replace allows you to swap values, it requires you to already have a replacement value ready.

By using take_mut::take, you can move the value out of the reference, perform complex transformations that require ownership—such as sorting or extending a collection—and then return the transformed value to the original location.

Sorting and Deduplicating Collections

When working with a Vec, certain operations like sort and dedup are typically performed via mutable references. However, if your transformation logic requires consuming the vector or reallocating it in a way that necessitates ownership, take_mut::take provides the necessary bridge. The closure receives the owned Vec, allowing you to perform any sequence of operations before returning it.

use take_mut::take;

fn main() {
let mut numbers = vec![5, 2, 8, 2, 5, 1, 8];

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

assert_eq!(numbers, vec![1, 2, 5, 8]);
}

Reversing and Extending Collections

Another scenario where take_mut::take is useful is when you need to combine multiple operations that might be more ergonomic with owned data. For instance, you might want to reverse a vector and then extend it with elements from another collection. By taking ownership, you can use methods that consume the collection or its components without worrying about the constraints of the original mutable reference until the transformation is complete.

use take_mut::take;

fn main() {
let mut items = vec![10, 20, 30];

// Use take to reverse the vector and extend it with new values
take(&mut items, |mut v| {
v.reverse();
v.extend(vec![40, 50]);
v
});

assert_eq!(items, vec![30, 20, 10, 40, 50]);
}

Safety and Panics

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. Because the memory location is temporarily invalid while the closure is running, take_mut must ensure that the program does not continue if the closure panics. If a panic occurs inside the closure, take_mut::take will abort the process to prevent the use of uninitialized memory.