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 valuesFnMut= can be called many times, but may mutate captured valuesFnOnce= 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
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 itemsFnMut: it changes the items in the backpackFnOnce: it takes an item out permanently and uses it up
Analogy
Imagine a lunchbox:
Fnopens the lunchbox, looks inside, maybe reads the label, then closes it unchangedFnMutopens the lunchbox and rearranges or modifies what is insideFnOnceopens 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.
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 out of the closure
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:
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
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;
});
();
}
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.
Comparisons
Closure traits compared
| Trait | Can be called more than once? | Can mutate captured values? | Can move captured values out? |
|---|---|---|---|
Fn | Yes | No | No |
FnMut | Yes | Yes | No |
FnOnce | Not necessarily | Yes, if owned appropriately | Yes |
Relationship between the traits
| If a closure implements... | Then it also implements... |
|---|---|
Fn | , |
Cheat Sheet
Quick rules
- Every closure implements
FnOnce - A closure implements
FnMutif it does not move captured values out of itself - A closure implements
Fnif it does not mutate captured values and does not move them out
Easy way to decide
Ask these questions in order:
- Does the closure move a captured value out when called?
- Yes -> only
FnOnce - No -> continue
- Yes -> only
- Does the closure mutate captured state?
- Yes ->
FnMutandFnOnce - No ->
Fn,FnMut, andFnOnce
- Yes ->
Trait ladder
Fn -> FnMut -> FnOnce
Meaning:
- anything that is
Fncan be used whereFnMutis expected - anything that is
FnMutcan be used where is expected
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:
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 acceptsFnMut(), and one that acceptsFnOnce(). - 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.
Keep learning
Related questions
Accessing Cargo Package Metadata in Rust
Learn how to read Cargo package metadata like version, name, and authors in Rust using compile-time environment macros.
Associated Types vs Generic Type Parameters in Rust: When to Use Each
Learn when to use associated types vs generic parameters in Rust traits, with clear rules, examples, and practical API design advice.
Convert an Integer to a String in Rust
Learn the current Rust way to convert integers to strings, why `to_str()` no longer works, and when to use `to_string()` or `format!`.