Closures
Closure Trait Selection
When you write a closure, the compiler analyzes how the closure body uses its captured variables to determine which of FnOnce, FnMut, and Fn the closure implements, and simultaneously determines whether the closure struct itself implements Copy and Clone.
Compiler Desugaring of a Closure into a Struct
Under the hood, every closure is compiled into an anonymous struct holding its captured variables plus implementations of the applicable Fn* traits:
Source Closure:
let factor = 3;
let scale = |x: i32| x * factor;
Compiler-Generated Representation (Conceptual):
struct __ClosureEnv<'a> {
factor: &'a i32,
}
impl<'a> FnOnce<(i32,)> for __ClosureEnv<'a> { ... }
impl<'a> FnMut<(i32,)> for __ClosureEnv<'a> { ... }
impl<'a> Fn<(i32,)> for __ClosureEnv<'a> { ... }
Decision Matrix: Capture Usage vs. Implemented Fn* Traits
Note that how a variable enters the closure (move vs. borrow) is independent from how the closure body uses it when called:
| How Captured Variables Are Used in the Body | Borrowed Capture (||) |
move Capture (move ||) |
|---|---|---|
| No captures at all | Fn + FnMut + FnOnce (and coerces to fn) |
Fn + FnMut + FnOnce (and coerces to fn) |
Only read (&self.field) |
Fn + FnMut + FnOnce |
Fn + FnMut + FnOnce |
Mutated (&mut self.field), never moved out |
FnMut + FnOnce |
FnMut + FnOnce |
Moved out of the closure on call (self.field) |
FnOnce only |
FnOnce only |
When Is a Closure Copy or Clone?
The compiler automatically implements Copy and Clone for a closure type if and only if all of its captured fields are Copy or Clone:
| Closure's Captured Fields | Closure Implements Copy? |
Closure Implements Clone? |
|---|---|---|
Shared references (&T) and Copy values (i32) only |
Yes | Yes |
Mutable reference (&mut T) |
No (&mut T is never Copy or Clone) |
No |
Owned non-Copy, Clone values (move with String) |
No | Yes |
fn main() {
let label = String::from("alpha");
// `move` closure owns `label` (String: Clone, !Copy):
let greeter = move || println!("Hello from {label}");
// Because `String: Clone`, the closure itself can be cloned!
let greeter_copy = greeter.clone();
greeter();
greeter_copy();
}
Hello from alpha
Hello from alpha
Guide for Selecting FnOnce, FnMut, or Fn in Your APIs
How does your function invoke the callback?
├── At most once (e.g., lazy fallback, thread spawn, Option::map)
│ └── Use `FnOnce` (most permissive for callers)
├── Multiple times sequentially (e.g., loop, Iterator::map, sort_by)
│ └── Use `FnMut` (allows stateful accumulators and read-only closures)
└── Concurrently across threads or via shared `&F` references
└── Use `Fn` (most restrictive for callers; guarantees no mutation)