Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

FnOnce / FnMut / Fn

Goal of This Episode

Understand that FnOnce, FnMut, and Fn are traits rather than types, grasp their inheritance relationships, and learn to choose the right closure trait.

Concept

They’re traits, Not Types

We’ve been saying FnOnce, FnMut, and Fn for several episodes without formally explaining — they are in fact traits. Like the Clone and Display you’ve already met, FnOnce / FnMut / Fn are traits defined in the standard library. Each closure’s anonymous struct automatically impls the corresponding traits (last episode’s inference rules decide which).

So what do these traits look like?

  • FnOnce(Args) -> Ret: callable once (the call may consume the closure, so further calls are not guaranteed).
  • FnMut(Args) -> Ret: callable repeatedly, with mutable access to captured state.
  • Fn(Args) -> Ret: callable repeatedly, without mutable access to captured state.

Watch out! fn(i32) -> i32 (lowercase) is the function pointer type, while Fn(i32) -> i32 (capitalized) is a trait. Two entirely different things.

The Inheritance Relationships

The three traits form supertrait relationships:

Fn : FnMut : FnOnce

Meaning:

  • Everything implementing Fn automatically implements FnMut and FnOnce.
  • Everything implementing FnMut automatically implements FnOnce.
  • But FnOnce doesn’t imply FnMut, nor FnMut imply Fn.

Why this direction?

  • FnFnMut: if a closure runs with just &self, using &mut self certainly works too (it simply uses a mutable reference where a shared one would have sufficed).
  • FnMutFnOnce: if a closure runs with &mut self, handing it self (full ownership) certainly works — owning a thing includes being able to modify it. It’s just that after the call the struct is consumed, so no second call.

The reverse doesn’t hold — a closure that must consume itself (FnOnce) can’t promise repeated calls (FnMut).

Accepting Closures with impl Trait

Remember Chapter 5’s impl Trait? Use it to accept closure parameters:

fn call_once(f: impl FnOnce() -> String) -> String {
    f()
}

fn call_many_times(mut f: impl FnMut()) {
    f();
    f();
    f();
}

fn call_twice(f: impl Fn() -> i32) -> i32 {
    f() + f()
}

fn main() {}

Note the mut on the FnMut parameter — calling an FnMut closure needs &mut self, so f itself must be mut.

Design Principle: Pick the Bound Accepting the Most Closures

When designing a function that takes a closure, choose the trait bound accepting the widest range of closures:

  1. Try FnOnce first — if you only call it once.
  2. Move to FnMut — if you need repeated calls.
  3. Only then Fn — if you need repeated calls without a mutable reference to the closure value.

Why? Because FnOnce accepts every closure (every closure implements FnOnce), while Fn accepts only closures callable through a shared reference. The widest bound gives callers maximum freedom.

In practice Fn is rarely needed — most functions calling a closure repeatedly do fine with FnMut (which also accepts Fn closures). Use Fn when the function needs to call the closure without a mutable reference to the closure value.

Function Pointers Implement All Three traits Too

Ordinary functions (and function pointers fn) automatically implement Fn, FnMut, and FnOnce. So a function name can be passed anywhere these three traits are accepted.

Example Code

// Only one call needed → FnOnce (accepts the most closures)
fn consume_and_print(f: impl FnOnce() -> String) {
    let result = f();
    println!("Result: {}", result);
}

// Repeated calls needed → FnMut
fn repeat_three_times(mut f: impl FnMut()) {
    f();
    f();
    f();
}

// Repeated calls without a mutable reference to the closure value → Fn
fn sum_two_calls(f: impl Fn(i32) -> i32, x: i32) -> i32 {
    f(x) + f(x)
}

fn main() {
    // FnOnce: the closure consumes a captured value
    let name = String::from("Rust");
    consume_and_print(|| {
        let s = name; // Moves name
        format!("Hello, {}!", s)
    });

    // FnMut: the closure modifies a captured variable
    let mut count = 0;
    repeat_three_times(|| {
        count += 1;
        println!("Call number {}", count);
    });
    println!("Called {} times in total", count);

    // Fn: the closure only reads
    let multiplier = 3;
    let result = sum_two_calls(|x| x * multiplier, 5);
    println!("sum_two_calls result: {}", result);

    // Ordinary functions can be passed in too
    fn double(x: i32) -> i32 {
        x * 2
    }
    let result2 = sum_two_calls(double, 10);
    println!("With an ordinary function: {}", result2);

    // An Fn closure also fits an FnOnce parameter (every Fn closure implements FnOnce)
    let greeting = String::from("Hi");
    consume_and_print(|| {
        format!("{}, world!", greeting) // Only reads greeting — it's Fn
    });
    // greeting survives, since the closure merely borrowed it
    println!("greeting is still here: {}", greeting);
}

Recap

  • FnOnce, FnMut, Fn are traits, not types; fn is the function pointer type.
  • The inheritance: FnFnMutFnOnce (FnOnce accepts every closure).
  • Accept closure parameters with impl FnOnce() / impl FnMut() / impl Fn().
  • FnMut parameters need mut.
  • Design principle for closure-taking functions: start with FnOnce, switch to FnMut for repeated calls, and use Fn when calls must not require a mutable reference to the closure value.
  • Function pointers automatically implement Fn + FnMut + FnOnce.