move Closures
Placing the move keyword before a closure's parameter list (move |params| body) forces the closure to take ownership of (or copy, for Copy types) every variable it references from the enclosing scope, even if the closure body only reads those variables.
Why move Closures Are Needed
By default, a closure that only reads an outer variable x captures &x by shared reference. If that closure is returned from the function or spawned onto a background thread, the stack frame holding x may be destroyed while the closure is still alive (E0373). Adding move transfers x directly into the closure's own storage so the closure no longer borrows the stack frame:
Without `move` (borrows stack): With `move` (self-contained):
Stack Frame Closure Stack Frame Closure
+-----------+ +---------+ +-----------+ +-------------+
| prefix | <──── | &prefix | | (moved) | | prefix: |
+-----------+ +---------+ +-----------+ | "[WORKER]" |
(Destroyed on return -> dangling!) +-------------+
use std::thread;
fn main() {
let prefix = String::from("[WORKER]");
let batch_size: usize = 64; // Copy type
// `move` moves `prefix` (String) and copies `batch_size` (usize) into the closure:
let handle = thread::spawn(move || {
println!("{prefix} processing {batch_size} items");
});
// `batch_size` is still usable here because `usize: Copy`:
println!("Main launched batch of {batch_size}");
handle.join().unwrap();
}
Main launched batch of 64
[WORKER] processing 64 items
Dangling Borrow Without move (E0373)
Returning a closure or spawning a thread that captures a local variable without move fails with E0373 because the closure may outlive the current function:
// ❌ does not compile
fn make_multiplier(factor: i32) -> impl Fn(i32) -> i32 {
|x| x * factor
}
fn main() {}
error[E0373]: closure may outlive the current function, but it borrows `factor`, which is owned by the current function
--> src/main.rs:3:5
|
3 | |x| x * factor
| ^^^ ------ `factor` is borrowed here
| |
| may outlive borrowed value `factor`
|
note: closure is returned here
--> src/main.rs:3:5
|
3 | |x| x * factor
| ^^^^^^^^^^^^^^
help: to force the closure to take ownership of `factor` (and any other referenced variables), use the `move` keyword
|
3 | move |x| x * factor
| ++++
Selective Reference Capture Inside a move Closure
If a move closure needs to take ownership of one variable (owned) while only borrowing another variable (shared), bind a reference (let shared_ref = &shared;) before the closure. The move closure then moves the reference shared_ref (which is Copy) by value while moving owned by value:
fn main() {
let owned = String::from("moved-in");
let shared = vec![10, 20, 30];
let shared_ref = &shared;
let closure = move || {
println!("owned = {owned}, shared len = {}", shared_ref.len());
};
closure();
// `shared` is still accessible in `main`, whereas `owned` was moved:
println!("shared still usable in main: {shared:?}");
}
owned = moved-in, shared len = 3
shared still usable in main: [10, 20, 30]