Skip to main content

Transform owned collections in place

When you need to perform operations on a collection that require full ownership—such as sorting or deduplicating a Vec—but you only have a mutable reference, Rust's standard library often forces you to use std::mem::replace with a dummy value. This can be inefficient or impossible if the type does not implement Default. The take_mut::take function solves this by allowing you to temporarily move the value out of the reference, transform it, and move it back.

Sorting and Deduplicating in Place

A common scenario involves cleaning up a list of items. While Vec provides sort() and dedup() on mutable references, some complex transformations or custom collection types might require consuming the original value to produce a new one. Using take_mut::take, you can treat the Vec as an owned value inside a closure.

use take_mut::take;

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

// We use take to get ownership of the Vec inside the closure
take(&mut numbers, |mut v| {
v.sort();
v.dedup();
// The closure must return the owned Vec to put it back into the reference
v
});

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

Internally, take_mut::take uses std::ptr::read to move the value out of the mutable reference. After your closure executes and returns the transformed value, it uses std::ptr::write to restore the reference. This bypasses the need for a temporary "placeholder" value.

Reversing and Extending Collections

You can also use take_mut::take to perform multiple ownership-based operations in a single block. For instance, if you want to reverse a Vec and then extend it with new elements, you can do so by taking ownership of the vector, performing the mutations, and returning the result.

use take_mut::take;

fn main() {
let mut data = vec![10, 20, 30];
let extra = vec![40, 50];

take(&mut data, |mut v| {
v.reverse();
v.extend(extra);
v
});

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

Safety and Panics

Because take_mut::take leaves the memory location of the mutable reference temporarily uninitialized, it must ensure that the reference is never accessed in an invalid state. If the closure you provide panics, take_mut cannot safely restore the value. In this event, the library is designed to exit the entire process immediately (with status code 101) to prevent undefined behavior. This ensures that the "moved-from" state is never observed by other parts of your Rust program.