Rust Fn, FnMut & FnOnce
On the Closures page you learned how to write a closure, how it captures variables, and how it can change them. This page answers the next question: how do you write your own function that accepts a closure? And how do you hand a closure back from a function?
The answer is three small traits: Fn, FnMut and FnOnce. Think of them like the rules at a library. Some visitors only read the books (Fn). Some write notes in the margins (FnMut). And some take a book home and never bring it back (FnOnce). Rust looks at what your closure does, and gives it the matching label. If the traits look scary at first, don’t worry. There are only three, and the compiler picks the right one for you.
Why closures need traits at all
Section titled “Why closures need traits at all”Every closure has its own unique type, made up by the compiler. You can’t write that type’s name. Even two closures that look exactly the same have different types:
fn main() { let mut rules = vec![|price: u32| price * 2]; rules.push(|price: u32| price * 2);}error[E0308]: mismatched types --> src/main.rs:3:16 |3 | rules.push(|price: u32| price * 2); | ---- ^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure | = note: no two closures, even if identical, have the same type = help: consider boxing your closure and/or using it as a trait objectSo a function can’t say “give me a closure of type X”. Instead, it says “give me any type that can be called like this”. That’s a trait bound, just like the ones on the Generics and Traits pages:
fn price_after<F: Fn(u32) -> u32>(rule: F, price: u32) -> u32 { rule(price)}
fn main() { let coupon = 15; let half_price = |price: u32| price / 2; let use_coupon = |price: u32| price - coupon;
println!("{}", price_after(half_price, 80)); println!("{}", price_after(use_coupon, 80));}Output:
4065Read F: Fn(u32) -> u32 as: “F is some type you can call with a u32, and it gives back a u32.” Both closures fit, even though their types are different.
The three traits: Fn, FnMut and FnOnce
Section titled “The three traits: Fn, FnMut and FnOnce”The compiler looks at what the closure’s body does with the values it captured:
Fn: it only reads them. You can call it as many times as you like.FnMut: it changes them. You can call it many times, but it needsmut.FnOnce: it gives them away (moves them out). You can call it only once, because after that the value is gone.
fn main() { let shop = String::from("Corner Bakery");
// Fn: only reads `shop` let greet = || println!("Welcome to {shop}!"); greet(); greet();
// FnMut: changes `orders` let mut orders = 0; let mut take_order = || { orders += 1; println!("order #{orders} taken"); }; take_order(); take_order();
// FnOnce: hands `receipt` back to the caller let receipt = String::from("2 croissants, 1 coffee"); let hand_over = || receipt; let customer_copy = hand_over(); println!("customer has: {customer_copy}");}Output:
Welcome to Corner Bakery!Welcome to Corner Bakery!order #1 takenorder #2 takencustomer has: 2 croissants, 1 coffeehand_over returns receipt itself, not a copy. Once the receipt is handed over, the closure has nothing left to give. That’s why it’s FnOnce.
Here’s the picture to keep in your head. Imagine three circles, one inside the other:
- The big outer circle is
FnOnce. Every closure can be called at least once, so every closure is in here. - Inside it is a smaller circle,
FnMut: closures that can be called again and again. - In the very middle is
Fn: closures that can be called again and again without changing anything.
So every Fn closure is also an FnMut and an FnOnce. This matters when you write a function. A parameter that asks for FnOnce accepts any closure. A parameter that asks for Fn is the pickiest one.
One thing that surprises people: the move keyword does not pick the trait. move || println!("{shop}") takes ownership of shop, but it only reads it, so it’s still Fn. Only the body decides.
Writing functions that take closures
Section titled “Writing functions that take closures”There are three ways to write the same bound. They all mean the same thing, so pick whichever reads best:
// 1. A generic parameter with a boundfn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 { f(x)}
// 2. `impl Fn` in argument position: shorter, no name neededfn apply_twice(f: impl Fn(i32) -> i32, x: i32) -> i32 { f(f(x))}
// 3. A `where` clause: tidy when the bound gets longfn apply_to_all<F>(f: F, scores: &[i32]) -> Vec<i32>where F: Fn(i32) -> i32,{ scores.iter().map(|&s| f(s)).collect()}
fn main() { let bonus = 10; let add_bonus = |score: i32| score + bonus;
println!("{}", apply(add_bonus, 50)); println!("{}", apply_twice(add_bonus, 50)); println!("{:?}", apply_to_all(add_bonus, &[40, 65, 90]));}Output:
6070[50, 75, 100]You might wonder how we could pass add_bonus three times. A closure that only reads its captures is cheap to copy, so Rust copies it each time.
Now FnMut and FnOnce. With FnMut, the parameter needs mut, because calling the closure changes what’s inside it. With FnOnce, you can call it once, and that’s it:
fn process_tasks<F: FnMut(&str)>(tasks: &[&str], mut on_done: F) { for task in tasks { on_done(task); }}
fn on_shutdown<F: FnOnce()>(cleanup: F) { println!("shutting down..."); cleanup();}
fn main() { let mut finished = Vec::new(); process_tasks(&["send emails", "back up database"], |task| { finished.push(task.to_string()); }); println!("finished: {:?}", finished);
on_shutdown(|| { // This loop takes ownership of `finished`, so the closure is FnOnce for task in finished { println!("archived: {task}"); } });}Output:
finished: ["send emails", "back up database"]shutting down...archived: send emailsarchived: back up databaseA good rule of thumb: ask for the loosest trait your function can live with. If you call the closure only once, ask for FnOnce, and callers can pass anything. You’ll see this in the standard library too: Option::map takes FnOnce, while Iterator::map takes FnMut.
When you pick the wrong bound
Section titled “When you pick the wrong bound”The compiler catches every mismatch, and its messages are very friendly here. Say a function asks for Fn, but your closure changes a counter:
fn run_report<F: Fn()>(f: F) { f(); f();}
fn main() { let mut runs = 0; run_report(|| { runs += 1; println!("report run {runs}"); });}error[E0594]: cannot assign to `runs`, as it is a captured variable in a `Fn` closure --> src/main.rs:9:9 |1 | fn run_report<F: Fn()>(f: F) { | - change this to accept `FnMut` instead of `Fn`...8 | run_report(|| { | ---------- -- in this closure | | | expects `Fn` instead of `FnMut`9 | runs += 1; | ^^^^^^^^^ cannot assignIt even tells you the fix: accept FnMut, and add mut to the parameter. With that change, the program prints report run 1 and report run 2:
fn run_report<F: FnMut()>(mut f: F) { f(); f();}The other classic mistake is calling an FnOnce closure twice:
fn main() { let report = String::from("Q3 sales"); let send = || { let sent = report; println!("sending {sent}"); }; send(); send();}error[E0382]: use of moved value: `send` --> src/main.rs:8:5 |7 | send(); | ------ `send` moved due to this call8 | send(); | ^^^^ value used here after move |note: closure cannot be invoked more than once because it moves the variable `report` out of its environment --> src/main.rs:4:20 |4 | let sent = report; | ^^^^^^The note says it plainly: the first call gave report away, so there’s nothing left for a second call. If you really need two calls, borrow instead (let sent = &report;) and the closure becomes Fn. If you pass a closure like this to a function that asks for Fn, you get a similar message: error[E0507]: cannot move out of report, a captured variable in an Fn closure.
Returning closures with impl Fn
Section titled “Returning closures with impl Fn”A function can also build a closure and hand it back. You write the return type as impl Fn(i32) -> i32, which means “some closure type; you don’t need to know its name”:
fn make_adder(amount: i32) -> impl Fn(i32) -> i32 { move |x| x + amount}
fn make_multiplier(factor: i32) -> impl Fn(i32) -> i32 { move |x| x * factor}
fn main() { let add_tip = make_adder(5); let triple = make_multiplier(3);
println!("{}", add_tip(20)); println!("{}", triple(7)); println!("{}", add_tip(triple(10)));}Output:
252135Why the move? Without it, the closure would only borrow amount. But amount belongs to make_adder, and it disappears the moment make_adder returns. The closure would be holding a reference to nothing. Rust refuses:
error[E0373]: closure may outlive the current function, but it borrows `amount`, which is owned by the current function --> src/main.rs:2:5 |2 | |x| x + amount | ^^^ ------ `amount` is borrowed here | | | may outlive borrowed value `amount` |help: to force the closure to take ownership of `amount` (and any other referenced variables), use the `move` keyword |2 | move |x| x + amount | ++++With move, the closure packs its own copy of amount and carries it along, like taking your lunch with you instead of leaving it in someone else’s fridge.
Boxed closures: many closures, one type
Section titled “Boxed closures: many closures, one type”impl Fn stands for one hidden type. So you can’t return one closure from the if branch and a different one from the else branch. You also can’t put different closures in the same Vec. For both jobs, put each closure in a box: Box<dyn Fn(f64) -> f64> means “any closure with this shape, stored on the heap”. It’s the same idea as the Trait Objects page.
Here’s a checkout that applies a list of named price rules, in order:
fn shipping_rule(express: bool, fee: f64) -> Box<dyn Fn(f64) -> f64> { if express { Box::new(move |total| total + fee * 2.0) } else { Box::new(move |total| total + fee) }}
fn main() { let member_percent = 10.0; let coupon = 5.0;
let rules: Vec<(&str, Box<dyn Fn(f64) -> f64>)> = vec![ ("member discount", Box::new(move |total: f64| total * (1.0 - member_percent / 100.0))), ("coupon", Box::new(move |total: f64| total - coupon)), ("standard shipping", shipping_rule(false, 3.5)), ];
let mut total = 80.0; println!("start: {total:.2}"); for (name, rule) in &rules { total = rule(total); println!("after {name}: {total:.2}"); }}Output:
start: 80.00after member discount: 72.00after coupon: 67.00after standard shipping: 70.50Boxing costs a tiny heap allocation, and each call goes through a pointer. That’s almost never a problem. Use impl Fn when there’s one closure type, and Box<dyn Fn> when there are many.
Storing a closure in a struct
Section titled “Storing a closure in a struct”A struct can hold a closure too. Since you can’t name the closure’s type, you make the struct generic over it. Here’s a small button that runs some code when clicked:
struct Button<F: Fn()> { label: String, on_click: F,}
impl<F: Fn()> Button<F> { fn click(&self) { println!("[{}] clicked", self.label); (self.on_click)(); }}
fn main() { let user = String::from("Ada"); let save = Button { label: String::from("Save"), on_click: move || println!("saving {user}'s draft"), };
save.click(); save.click();}Output:
[Save] clickedsaving Ada's draft[Save] clickedsaving Ada's draftNotice the parentheses in (self.on_click)(). They tell Rust “take the field, then call it”. If the button needs to change its captures on each click, use F: FnMut() and make the method take &mut self.
Function pointers: fn(i32) -> i32
Section titled “Function pointers: fn(i32) -> i32”Regular functions can be passed around too. Their type is written with a small fn, like fn(i32) -> i32. This is a function pointer, a plain address of some code. A closure that captures nothing can turn into one as well:
fn double(x: i32) -> i32 { x * 2}
fn square(x: i32) -> i32 { x * x}
fn apply_op(op: fn(i32) -> i32, x: i32) -> i32 { op(x)}
fn main() { println!("{}", apply_op(double, 4)); println!("{}", apply_op(|x| x - 1, 4));
let steps: [fn(i32) -> i32; 3] = [double, square, |x| x + 1]; let mut value = 3; for step in steps { value = step(value); } println!("{value}");}Output:
8337Function pointers all share one type, so you can put them in an array with no boxing. The catch is that a closure which captures something can’t become a function pointer. The compiler says: closures can only be coerced to fn types if they do not capture any variables. The good news goes the other way: every regular function also implements Fn, FnMut and FnOnce, so you can pass double to apply from earlier. That’s why most code uses the closure traits: they accept both.
Common mistakes
Section titled “Common mistakes”Forgetting mut on an FnMut parameter. Calling an FnMut changes it, so its binding must be mut:
error[E0596]: cannot borrow `on_done` as mutable, as it is not declared as mutable --> src/main.rs:3:9 |3 | on_done(task); | ^^^^^^^ cannot borrow as mutable |help: consider changing this to be mutable |1 | fn process_tasks<F: FnMut(&str)>(tasks: &[&str], mut on_done: F) { | +++Returning different closures from -> impl Fn. Two closures are two types, even if they look alike:
fn shipping_rule(express: bool, fee: f64) -> impl Fn(f64) -> f64 { if express { move |total| total + fee * 2.0 } else { move |total| total + fee }}error[E0308]: `if` and `else` have incompatible types --> src/main.rs:5:9 |2 | / if express {3 | | move |total| total + fee * 2.0 | | ------------------------------ | | | | | the expected closure | | expected because of this4 | | } else {5 | | move |total| total + fee | | ^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure6 | | } | |_____- `if` and `else` have incompatible types | = note: expected closure `{closure@src/main.rs:3:9: 3:21}` found closure `{closure@src/main.rs:5:9: 5:21}` = note: no two closures, even if identical, have the same type = help: consider boxing your closure and/or using it as a trait objecthelp: you could change the return type to be a boxed trait object |1 - fn shipping_rule(express: bool, fee: f64) -> impl Fn(f64) -> f64 {1 + fn shipping_rule(express: bool, fee: f64) -> Box<dyn Fn(f64) -> f64> { |help: if you change the return type to expect trait objects, box the returned expressions |3 ~ Box::new(move |total| total + fee * 2.0)4 | } else {5 ~ Box::new(move |total| total + fee) |Do what the compiler suggests: return Box<dyn Fn(f64) -> f64> and wrap each closure in Box::new(...).
Calling a closure field like a method. Writing self.on_click() makes Rust look for a method named on_click:
error[E0599]: no method named `on_click` found for reference `&Button<F>` in the current scope --> src/main.rs:9:14 |9 | self.on_click(); | ^^^^^^^^ field, not a method |help: to call the type parameter stored in `on_click`, surround the field access with parentheses |9 | (self.on_click)(); | + +Practice
Section titled “Practice”1. A ticket dispenser
Section titled “1. A ticket dispenser”Write a function ticket_dispenser(start: u32) that returns a closure. Each call to the closure gives the next ticket number: start, then start + 1, and so on. Make two dispensers (a bakery starting at 100, a pharmacy starting at 1) and show that they count separately. Hint: the closure changes its own counter, so the return type is impl FnMut() -> u32, and you’ll need move.
Show solution
fn ticket_dispenser(start: u32) -> impl FnMut() -> u32 { let mut next = start; move || { let ticket = next; next += 1; ticket }}
fn main() { let mut bakery = ticket_dispenser(100); let mut pharmacy = ticket_dispenser(1);
println!("bakery: {}", bakery()); println!("bakery: {}", bakery()); println!("pharmacy: {}", pharmacy()); println!("bakery: {}", bakery());}Output:
bakery: 100bakery: 101pharmacy: 1bakery: 102Each dispenser moved its own next inside, so they never share a counter. The variables bakery and pharmacy need mut because they are FnMut.
2. A retry helper
Section titled “2. A retry helper”Write retry(max_attempts, task). It calls task until it returns Ok, or until it has tried max_attempts times. Print a line for each failed attempt. Test it with a closure that fails twice with "server busy", then succeeds. Hint: the test closure counts its own calls, so the bound is FnMut() -> Result<String, String>, and the parameter needs mut.
Show solution
fn retry<F>(max_attempts: u32, mut task: F) -> Result<String, String>where F: FnMut() -> Result<String, String>,{ for attempt in 1..=max_attempts { match task() { Ok(value) => return Ok(value), Err(e) => println!("attempt {attempt} failed: {e}"), } } Err(String::from("gave up"))}
fn main() { let mut calls = 0; let result = retry(5, || { calls += 1; if calls < 3 { Err(String::from("server busy")) } else { Ok(String::from("data downloaded")) } }); println!("{:?} after {calls} calls", result);}Output:
attempt 1 failed: server busyattempt 2 failed: server busyOk("data downloaded") after 3 callsretry calls the task more than once, so FnOnce won’t do, and the task changes calls, so Fn won’t do either. FnMut is exactly right. When retry returns, the closure is done, so main can read calls again.
- Every closure has its own unique type, so functions accept closures through a trait bound like
F: Fn(i32) -> i32. Fnonly reads its captures,FnMutchanges them, andFnOncemoves them out and can be called once. The body decides, notmove.- Every
Fnis alsoFnMutandFnOnce. Ask for the loosest trait your function needs. - Write bounds as
<F: Fn(..)>,impl Fn(..), or in awhereclause.FnMutparameters needmut. - Return one closure with
-> impl Fn(..)(usually withmove). UseBox<dyn Fn(..)>for different closures from branches or in aVec. fn(i32) -> i32is a function pointer. Regular functions and non-capturing closures fit it.
Quick check
Section titled “Quick check”Quick check
1. A closure does total += price on a captured variable. Which is the strictest trait it implements?
2. Your function calls its closure parameter exactly once. Which bound accepts the most closures?
3. Why does make_adder(amount: i32) -> impl Fn(i32) -> i32 need move |x| x + amount?
4. You want a Vec holding several different discount closures. What type do the elements need?
Score: 0 / 4
Read more
Section titled “Read more”- Moving Captured Values Out of Closures and the Fn Traits — The Rust Book: the official explanation of how the compiler picks
Fn,FnMutorFnOnce. Fn,FnMutandFnOnce— standard library docs: each trait’s definition, with short examples of when to use it.- Input parameters — Rust by Example: runnable examples of functions that take closures with each of the three bounds.
- Output parameters — Rust by Example: returning closures with
impl Fn, and whymoveis needed. - Closure types — The Rust Reference: the exact rules for how closures capture values and which traits they implement.