Essential Standard Traits

Fn, FnMut, and FnOnce

The Fn, FnMut, and FnOnce traits in std::ops represent callable values (closures and function pointers), classified by how they access variables captured from their enclosing environment.

Trait Hierarchy

The three callable traits form a strict supertrait hierarchy:

      FnOnce          (consumes self; can be called at least once)
        ▲
        │  supertrait
      FnMut           (takes &mut self; can mutate captured state)
        ▲
        │  supertrait
       Fn             (takes &self; reads captured state immutably)

Because Fn: FnMut and FnMut: FnOnce:

  • Every Fn closure also implements FnMut and FnOnce.
  • Every FnMut closure also implements FnOnce.
  • Plain function pointers (fn(A) -> R) and non-capturing closures implement all three: Fn, FnMut, and FnOnce.

How Capture Mode Determines Implemented Traits

The compiler automatically implements the most permissive traits possible for a closure based on what the closure body does with its captured variables:

What the Closure Body Does with Captures Receiver Traits Implemented
Does not capture, or only reads captures (&T) &self Fn, FnMut, FnOnce
Mutates at least one captured variable (&mut T), moves none out &mut self FnMut, FnOnce
Moves a non-Copy captured value out of the closure self FnOnce only
fn call_once<F: FnOnce() -> String>(f: F) -> String {
    f()
}

fn call_mut<F: FnMut()>(mut f: F) {
    f();
    f();
}

fn call_immut<F: Fn() -> usize>(f: F) -> usize {
    f() + f()
}

fn main() {
    let label = String::from("metrics");

    // 1. Only reads `label` -> implements Fn + FnMut + FnOnce
    let reader = || label.len();
    println!("Read twice: {}", call_immut(reader));

    // 2. Mutates `counter` -> implements FnMut + FnOnce
    let mut counter = 0;
    call_mut(|| counter += 1);
    println!("Counter after call_mut: {counter}");

    // 3. Moves `label` out of environment -> implements FnOnce only
    let consumer = || {
        let owned = label;
        owned + "_done"
    };
    println!("Consumed: {}", call_once(consumer));
}
Read twice: 14
Counter after call_mut: 2
Consumed: metrics_done

Choosing a Closure Bound in Function Signatures

When writing a higher-order function that accepts a callback:

  • Prefer FnOnce if the function invokes the callback at most once (for example, Option::unwrap_or_else), as it accepts all closures.
  • Use FnMut if the function invokes the callback multiple times sequentially (for example, Iterator::map or slice::sort_by), allowing callers to maintain mutable state across calls.
  • Use Fn only when the callback must be called concurrently from multiple threads or aliased through shared references.