Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A move closure in Rust is an anonymous function that forces the capture of its environment by value, transferring ownership of the captured variables from the enclosing scope into the closure’s internal state. By prepending the move keyword to a closure, you explicitly override Rust’s default behavior of inferring the capture method (borrowing or moving) based on usage.

Syntax

let closure_name = move |param1: Type| -> ReturnType {
    // closure body
};

Capture Mechanics

Under the hood, the Rust compiler represents every closure as a unique, anonymous struct, where the captured variables are stored as fields.
  • Default Behavior: Without move, the compiler infers the least restrictive capture method based on usage: shared reference (&T), mutable reference (&mut T), or by value (T). The struct fields correspond to these inferred types (references or actual values).
  • Move Behavior: The move keyword forces all captured variables to be captured by value (T). The closure takes full ownership of the data, and the struct fields contain the actual values rather than references.
If a captured variable implements the Copy trait (e.g., i32, bool), the move keyword forces a bitwise copy of the value into the closure’s state. If the variable does not implement Copy (e.g., String, Vec<T>), the value is strictly moved, rendering the original variable inaccessible in the outer scope.
let heap_data = String::from("Owned by closure");
let stack_data = 42; // Implements Copy

let forced_capture = move || {
    println!("Heap: {}", heap_data);
    println!("Stack: {}", stack_data);
};

// ERROR: `heap_data` was moved into the closure and is no longer valid here.
// println!("{}", heap_data); 

// VALID: `stack_data` was copied into the closure. The outer scope retains its own copy.
println!("{}", stack_data); 

Interaction with Closure Traits

A common misconception is that a move closure automatically implements only the FnOnce trait. The move keyword dictates how variables are captured (at creation time), while the Fn, FnMut, and FnOnce traits dictate how the closure can be invoked (at execution time). These traits utilize inheritance: a closure implementing Fn also implements FnMut and FnOnce, and a closure implementing FnMut also implements FnOnce. A move closure will implement the most restrictive trait required by its body:
  1. Fn: The closure only reads the data it owns. It can be called multiple times via shared references (&self). It can only be called concurrently across multiple threads if the captured data implements the Sync trait.
  2. FnMut: The closure mutates the data it owns. It requires the closure itself to be declared as mut and takes a mutable reference (&mut self). It can be called multiple times sequentially, but not concurrently.
  3. FnOnce: The closure consumes (moves out of) the data it owns. It takes ownership of itself (self) and can only be called exactly once.
// Example: A move closure implementing FnMut (and by inheritance, FnOnce)
let mut counter = 0; // Implements Copy

// `move` forces a copy of `counter` into the closure's internal struct.
// The closure body mutates this internal state, so it implements `FnMut`.
let mut increment = move || {
    counter += 1; 
    println!("Internal: {}", counter);
};

increment(); // Internal: 1
increment(); // Internal: 2

// The external variable remains untouched because the closure operates on its owned copy.
println!("External: {}", counter); // External: 0
Master Rust with Deep Grasping Methodology!Learn More