Question

When Rust Closures Implement Fn, FnMut, and FnOnce

rustclosures

Question

In Rust, what specific conditions determine whether a closure implements the Fn, FnMut, and FnOnce traits?

More specifically:

  • When does a closure fail to implement FnOnce?
  • When does a closure fail to implement FnMut?
  • When does a closure fail to implement Fn?

For example, if a closure mutates captured state inside its body, the compiler will not allow it to implement Fn. I want to understand the exact rules the compiler uses for all three closure traits.

Short Answer

By the end of this page, you will understand how Rust decides whether a closure implements Fn, FnMut, and FnOnce. You will learn that every closure implements FnOnce, but only some also implement FnMut, and only a smaller set implement Fn. The key idea is how the closure uses its captured variables: moving values out limits it to FnOnce, mutating captured values allows FnMut but not Fn, and only read-only access allows Fn.

Concept

Rust closures automatically implement one, two, or all three of the closure traits based on how they use captured values.

The three traits form a ladder:

  • Fn = can be called many times without mutating or consuming captured values
  • FnMut = can be called many times, but may mutate captured values
  • FnOnce = can be called at least once, and may consume captured values

A very important rule is:

  • Every closure implements FnOnce

That means the answer to "When does a closure not implement FnOnce?" is:

  • Never for normal closures

Why? Because any closure can always be called once by consuming the closure itself.

The core rule

Rust looks at what the closure body does with the variables it captures from the surrounding scope.

A closure implements Fn if

  • it does not move captured values out of itself
  • it does not mutably borrow or mutate captured values
  • it only reads captured values, or captures nothing

A closure implements FnMut if

  • it does not move captured values out of itself
  • but it may mutate captured values or take mutable borrows of them

A closure implements FnOnce if

  • it may move captured values out of itself
  • or otherwise consume captured state during the call

Why this matters

These traits are used everywhere in Rust APIs:

  • iterator adapters like .map() and .filter()
  • callbacks
  • event handlers
  • retry logic
  • thread spawning
  • one-time initialization

If a function expects an Fn, you can pass only closures that are safe to call repeatedly without changing or consuming their environment. If it expects FnMut, mutation is allowed. If it expects FnOnce, the closure may consume what it captured.

Trait relationship

The traits are related like this:

  • Fn is the most restrictive
  • FnMut is less restrictive
  • FnOnce is the least restrictive

In practice:

  • if a closure implements Fn, it also implements FnMut and FnOnce
  • if a closure implements FnMut, it also implements FnOnce
  • if a closure implements only FnOnce, it cannot be reused safely

So the main question is usually not whether a closure implements FnOnce, but whether it is also reusable as FnMut or Fn.

Mental Model

Think of a closure as a small backpack that carries values from the surrounding scope.

When you call the closure, Rust asks: what does this closure do with the items in its backpack?

  • Fn: it only looks at the items
  • FnMut: it changes the items in the backpack
  • FnOnce: it takes an item out permanently and uses it up

Analogy

Imagine a lunchbox:

  • Fn opens the lunchbox, looks inside, maybe reads the label, then closes it unchanged
  • FnMut opens the lunchbox and rearranges or modifies what is inside
  • FnOnce opens the lunchbox and eats the sandwich, so the same lunchbox content cannot be used the same way again

That is why FnOnce may be callable only once: the closure may consume part of its captured state.

Take Quiz

Syntax and Examples

Basic syntax

The traits are usually seen in generic bounds:

fn call_fn<F: Fn()>(f: F) {
    f();
}

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

fn call_fnonce<F: FnOnce()>(f: F) {
    f();
}

Example 1: Closure that implements Fn

fn main() {
    let name = String::from("Rust");

    let print_name = || println!("Hello, {name}!");

    print_name();
    print_name();
}

This closure only reads name.

  • It does not mutate name
  • It does not move name out of the closure

So it implements:

  • Fn
  • FnMut
  • FnOnce

Example 2: Closure that implements FnMut but not Fn

fn main() {
    let mut count = 0;

    let mut increment = || {
        count += 1;
        println!("count = {count}");
    };

    increment();
    increment();
}

This closure mutates captured state.

  • It can still be called multiple times
  • But because it mutates its environment, it does not implement Fn

So it implements:

  • FnMut
  • FnOnce

But not:

  • Fn

Example 3: Closure that implements only FnOnce

fn main() {
    let text = String::from("hello");

    let consume = || {
        let moved = text;
        println!("{moved}");
    };

    consume();
}

This closure moves text out of its captured environment when called.

After that, the captured value is gone.

So it implements:

  • FnOnce

But not:

  • FnMut
  • Fn

Example 4: A move closure does not automatically mean FnOnce

fn main() {
    let x = 10;

    let print_x = move || println!("x = {x}");

    print_x();
    print_x();
}

Even though this is a move closure, it only reads x.

move affects how values are captured, not automatically how they are used later.

This closure can still implement Fn.

That is an important beginner point:

  • move does not always mean FnOnce
  • moving a captured value out inside the body is what forces FnOnce

Step by Step Execution

Consider this closure:

fn main() {
    let mut total = 0;

    let mut add_one = || {
        total += 1;
        println!("total = {total}");
    };

    add_one();
    add_one();
}

Step-by-step

1. total is created

let mut total = 0;

A mutable integer exists in the surrounding scope.

2. The closure is created

let mut add_one = || {
    total += 1;
    println!("total = {total}");
};

Rust sees that the closure uses total and captures it.

Because the closure does this:

total += 1;

it must capture total in a way that allows mutation.

3. Rust determines the trait

The closure:

  • does not move total out
  • does mutate captured state

So:

  • Fn is not allowed
  • FnMut is allowed
  • FnOnce is also allowed

4. First call

add_one();

The closure runs:

  • total changes from 0 to 1
  • prints total = 1

5. Second call

add_one();

The closure still has access to the same captured total:

  • total changes from 1 to 2
  • prints total = 2

Why not Fn?

Because Fn requires calling through an immutable reference to the closure. If the closure needs to change its captured state, immutable access is not enough.

Why still FnOnce?

Because anything callable as FnMut is also callable once by value.

Real World Use Cases

1. Read-only callbacks with Fn

Use Fn when a callback should be safe to call many times without changing its environment.

Examples:

  • formatting log messages
  • checking whether a feature flag is enabled
  • filtering items using shared read-only configuration
fn run_twice<F: Fn()>(f: F) {
    f();
    f();
}

2. Stateful processing with FnMut

Use FnMut when the closure needs to keep or update state between calls.

Examples:

  • counting how many items were processed
  • building up metrics
  • assigning sequence numbers
  • caching simple intermediate state
let mut count = 0;
let mut process = |_| {
    count += 1;
};

This is common in iterator pipelines.

3. One-time ownership transfer with FnOnce

Use FnOnce when the closure needs to consume something it captured.

Examples:

  • moving a String into a worker task
  • transferring ownership into a thread
  • one-time cleanup logic
  • deferred execution that consumes resources
let data = String::from("job data");
let job = move || {
    println!("processing {data}");
};

If the closure consumes data, it may only be callable once.

Take Quiz

Real Codebase Usage

In real Rust projects, developers choose closure trait bounds based on how often the callback should be reusable and whether it needs state.

Common patterns

Guard-like read-only checks use Fn

fn validate_with<F: Fn(&str) -> bool>(input: &str, check: F) -> bool {
    check(input)
}

This is useful for:

  • validation rules
  • predicates
  • configuration checks
  • access-control checks

Iteration counters and accumulators use FnMut

Many iterator methods accept FnMut because the closure is called multiple times and often updates state.

fn main() {
    let items = vec![1, 2, 3];
    let mut sum = 0;

    items.iter().for_each(|x| {
        sum += x;
    });

    println!("sum = {sum}");
}

The closure mutates sum, so FnMut is the right fit.

Deferred ownership transfer uses FnOnce

APIs that run a task one time often accept FnOnce.

fn run_job<F: FnOnce()>(job: F) {
    job();
}

This is common when:

  • starting a thread
  • executing a one-time task
  • moving owned data into a callback
  • finalizing resources

Practical API design tip

When writing your own functions, prefer the least restrictive bound that still works:

  • use FnOnce if the function calls the closure once
  • use FnMut if the function calls it multiple times and mutation may be useful
  • use Fn if the function calls it multiple times and wants to allow only read-only closures

This makes your API more flexible for callers.

Common Mistakes

Mistake 1: Thinking some closures do not implement FnOnce

This is the biggest misconception.

let x = 5;
let c = || println!("{x}");

This closure implements FnOnce too.

Rule

  • All closures implement FnOnce
  • Some also implement FnMut
  • Some also implement Fn

Mistake 2: Assuming move means only FnOnce

Broken assumption:

let x = String::from("hello");
let c = move || println!("{x}");

Beginners often think this must be FnOnce only.

But this closure only reads x, so it can still be called multiple times.

Fix

Focus on what happens inside the body, not only how capture happens.

Mistake 3: Mutating captured state and expecting Fn

let mut count = 0;
let add = || {
    count += 1;
};

This closure cannot implement Fn because it mutates captured state.

Fix

Use an FnMut bound when your closure needs to change its environment.

Mistake 4: Moving out of a captured value accidentally

let text = String::from("hello");
let consume = || {
    let taken = text;
    println!("{taken}");
};

This consumes text when called, so the closure becomes FnOnce only.

Fix

Borrow instead of moving if you want repeated calls:

let text = String::from("hello");
let show = || {
    println!("{text}");
};

Mistake 5: Forgetting that calling an FnMut closure requires a mutable binding

Broken code:

let mut count = 0;
let increment = || {
    count += 1;
};

increment();

This fails because calling an FnMut closure requires mutable access to the closure value.

Fix

let mut count = 0;
let mut increment = || {
    count += 1;
};

increment();

The closure variable itself must be mut.

Comparisons

Closure traits compared

TraitCan be called more than once?Can mutate captured values?Can move captured values out?
FnYesNoNo
FnMutYesYesNo
FnOnceNot necessarilyYes, if owned appropriatelyYes

Relationship between the traits

If a closure implements...Then it also implements...
FnFnMut, FnOnce
FnMutFnOnce
FnOncenothing more is guaranteed

move vs closure traits

IdeaMeaning
move closureCaptures values by ownership when possible
FnOnce closureMay consume captured values when called

These are related but not identical.

Choosing a function bound

If your function...Preferred bound
calls the closure onceFnOnce
calls it multiple times and allows mutationFnMut
calls it multiple times and needs read-only behaviorFn
Take Quiz

Cheat Sheet

Quick rules

  • Every closure implements FnOnce
  • A closure implements FnMut if it does not move captured values out of itself
  • A closure implements Fn if it does not mutate captured values and does not move them out

Easy way to decide

Ask these questions in order:

  1. Does the closure move a captured value out when called?
    • Yes -> only FnOnce
    • No -> continue
  2. Does the closure mutate captured state?
    • Yes -> FnMut and FnOnce
    • No -> Fn, FnMut, and FnOnce

Trait ladder

Fn -> FnMut -> FnOnce

Meaning:

  • anything that is Fn can be used where FnMut is expected
  • anything that is FnMut can be used where FnOnce is expected

Common examples

Read only

let x = 1;
let c = || println!("{x}");

Implements: Fn, FnMut, FnOnce

Mutates capture

let mut x = 1;
let mut c = || x += 1;

Implements: FnMut, FnOnce

Consumes capture

let s = String::from("hi");
let c = || drop(s);

Implements: FnOnce

Important note about move

let s = String::from("hi");
let c = move || println!("{s}");

This may still implement Fn.

move changes capture mode, not necessarily call trait behavior.

FAQ

Does every Rust closure implement FnOnce?

Yes. Every closure can be called at least once by consuming the closure value itself.

When does a closure implement only FnOnce?

When calling it moves a captured value out of the closure or otherwise consumes captured state.

Why does mutating captured state prevent Fn?

Because Fn is called through an immutable reference. If the closure needs to change its captured environment, immutable access is not enough.

Does move always make a closure FnOnce?

No. A move closure can still implement Fn or FnMut if it does not consume captured values during the call.

Why do many iterator methods use FnMut?

Because they call the closure multiple times, and allowing mutation makes the API more useful for counters, accumulation, and local state.

Should I use Fn, FnMut, or FnOnce in my own function signatures?

Use the least restrictive bound that matches your function:

  • one call: FnOnce
  • repeated calls with mutation allowed: FnMut
  • repeated calls with read-only behavior: Fn

Can a closure that captures nothing still implement all three traits?

Yes. A closure that captures nothing can implement Fn, FnMut, and FnOnce.

Take Quiz

Mini Project

Description

Build a small Rust program that demonstrates all three closure traits side by side. This helps you see how reading, mutating, and consuming captured values affect which trait a closure can satisfy.

Goal

Create three closures: one that is Fn, one that is FnMut, and one that is FnOnce, and pass each to a function with the appropriate trait bound.

Requirements

  • Write one function that accepts Fn(), one that accepts FnMut(), and one that accepts FnOnce().
  • Create three closures showing read-only access, mutable access, and consuming ownership.
  • Call each closure through the correct function.
  • Make sure the program compiles and prints output that shows the difference in behavior.
Take Quiz

Keep learning

Related questions

View more