---
title: "19.2 Closures and the Fn traits"
description: "How to take a closure as a parameter or return one, using the Fn, FnMut, and FnOnce traits, plus where plain function pointers fit."
url: "https://learnrust.net/chapter-19/closures-and-the-fn-traits/"
last_updated: "2026-06-13"
---

# 19.2 Closures and the Fn traits

In the previous lesson ([19.1](https://learnrust.net/chapter-19/closures/)) every closure stayed put: we made it and called it in the same function. The reason closures are everywhere in real Rust, though, is that you *pass them to other functions*. You tell `sort_by` how to compare, you tell `filter` what to keep, you tell a button what to do when clicked. To write a function that accepts a closure, you need a way to name a closure's type in a signature. That's what the **`Fn` traits** are for.

## Each closure has its own anonymous type

Here's the wrinkle. Two closures that look identical do not share a type:

```rust
let a = |x: i32| x + 1;
let b = |x: i32| x + 1;
```

`a` and `b` have *different* types, each one a unique, compiler-generated type with no name you could write. That makes sense once you remember a closure carries its captures: a closure is really a little anonymous struct holding the captured variables, with a call method attached. Two such structs are different types even when their code matches, the same way two different structs are different types.

So you can't write `fn apply(f: ???)` by naming the closure type, because it has no name. What closures *do* share is a trait: the trait that says "this can be called like a function." Three of them, actually, and the difference between them is exactly the chapter-8-and-9 distinction you already know.

## Fn, FnMut, FnOnce

A closure captures its environment by reference, by mutable reference, or by value (lesson [19.1](https://learnrust.net/chapter-19/closures/)). Calling it does the corresponding thing to those captures, and that determines which traits it implements:

**`FnOnce`** is the most permissive: it can be called, but possibly only *once*, because calling it might consume (move out) a captured value. Every closure implements `FnOnce`, since every closure can be called at least once.

**`FnMut`** can be called repeatedly and might *mutate* its captured values when called. It needs `&mut` access to the closure to do so.

**`Fn`** can be called repeatedly and only *reads* its captures (or captures nothing). It needs only `&` access, so it can even be called from several places at once.

These nest: every `Fn` is also an `FnMut` (reading repeatedly is a special case of mutating repeatedly), and every `FnMut` is also an `FnOnce` (anything callable many times is callable once). So when you *write* a function that takes a closure, you want the *most permissive* bound that your code actually needs, because that accepts the most closures. If you only call the closure once, ask for `FnOnce`. If you call it many times but don't need it to mutate, ask for `Fn`.

## Taking a closure as a parameter

The cleanest way to accept a closure is `impl Trait` in argument position, the syntax from lesson [16.4](https://learnrust.net/chapter-16/impl-trait/). Here's a function that calls the closure it's given twice, so it needs `Fn`:

```rust
fn do_twice(f: impl Fn()) {
    f();
    f();
}

fn main() {
    let name = String::from("world");
    do_twice(|| println!("hello, {name}"));
}
```

```
hello, world
hello, world
```

`impl Fn()` reads "some type that implements `Fn` and takes no arguments and returns nothing." The closure `|| println!("hello, {name}")` only reads `name`, so it implements `Fn`, and it's accepted. Because the bound is `Fn`, `do_twice` may call `f` as many times as it likes.

To accept a closure that returns a value, name the signature inside the trait. `Fn(i32) -> i32` means "callable with one `i32`, returning an `i32`":

```rust
fn apply_to_5(f: impl Fn(i32) -> i32) -> i32 {
    f(5)
}

fn main() {
    let factor = 3;
    println!("{}", apply_to_5(|x| x * factor));   // captures factor
    println!("{}", apply_to_5(|x| x + 1));
}
```

```
15
6
```

Both closures match `Fn(i32) -> i32`, and the first one quietly carries `factor` along. The caller of `apply_to_5` thinks only about the signature; the captures are the closure's private business.

If your function needs to mutate through the closure, ask for `FnMut`, and the parameter must be `mut`:

```rust
fn call_n_times(mut f: impl FnMut(), n: usize) {
    for _ in 0..n {
        f();
    }
}

fn main() {
    let mut count = 0;
    call_n_times(|| count += 1, 3);
    println!("{count}");
}
```

```
3
```

> **Best practice**
>
> When writing a function that takes a closure, ask for the *most permissive* trait your body actually requires: `FnOnce` if you call it at most once, `FnMut` if you call it repeatedly and need mutation, `Fn` if you only read. A looser bound accepts more closures. Reach for a tighter one only when your code genuinely needs that capability.

## Returning a closure

A closure has no nameable type, so to *return* one you again use `impl Trait`, this time in return position. There's one catch: a returned closure usually captures locals from the function, and those locals are about to disappear when the function ends, so the closure must *own* its captures. That's the `move` from lesson [19.1](https://learnrust.net/chapter-19/closures/), now load-bearing:

```rust
fn make_adder(n: i32) -> impl Fn(i32) -> i32 {
    move |x| x + n
}

fn main() {
    let add_ten = make_adder(10);
    println!("{}", add_ten(5));
    println!("{}", add_ten(100));
}
```

```
15
110
```

`make_adder` returns "some `Fn(i32) -> i32`." The `move` is mandatory: without it the closure would borrow `n`, but `n` is a local that dies when `make_adder` returns, so the borrow would dangle, exactly the dangling-reference error chapter 9 trained you to expect. With `move`, the closure owns its own copy of `n` and is free to outlive the function that built it. This is the standard recipe for "a function that builds and hands back behavior."

## Function pointers, briefly

Closures that capture *nothing* are interchangeable with plain functions, and both can be passed where an `Fn` is expected. There's also a concrete type for "a plain function, no captures": the function pointer `fn` (lowercase, a type, distinct from the `fn` keyword that defines functions):

```rust
fn double(x: i32) -> i32 { x * 2 }

fn apply(f: fn(i32) -> i32, x: i32) -> i32 {
    f(x)
}

fn main() {
    println!("{}", apply(double, 5));      // a named function
    println!("{}", apply(|x| x * 2, 5));   // a non-capturing closure
}
```

```
10
10
```

A `fn` pointer accepts both named functions and non-capturing closures, but never a capturing one, since there's nowhere to store the captures. In practice you'll reach for the `Fn` traits the vast majority of the time, because they accept everything `fn` does *plus* capturing closures. The `fn` pointer type is worth recognizing when you meet it (it shows up in C interop, chapter 25, where captures aren't an option), but `impl Fn` is the default tool.

> **For advanced readers**
>
> `impl Fn` in return position works for a *single* closure type. If a function has two branches that each return a *different* closure, they have different anonymous types and `impl Fn` won't unify them, you'll get a type-mismatch error. The fix is a trait object on the heap, `Box<dyn Fn(i32) -> i32>` (trait objects from lesson [16.9](https://learnrust.net/chapter-16/trait-objects/), `Box` from chapter 21), which erases the concrete types behind one pointer. Reach for it only when you actually need to return different closures from different paths.

## Quiz time

**Question #1**

Why can't you write a function parameter type as the literal type of a specific closure?

<details class="solution">
<summary>Show solution</summary>

Because each closure has its own unique, compiler-generated anonymous type with no name you can write in source. Even two textually identical closures have different types. You name closures in signatures through the traits they share instead, `Fn`, `FnMut`, or `FnOnce` (via `impl Fn(...) -> ...` or a generic bound), not through a concrete type name.

</details>

**Question #2**

What's the difference between `Fn`, `FnMut`, and `FnOnce`, and which should a function parameter ask for?

<details class="solution">
<summary>Show solution</summary>

`Fn` only reads its captures and can be called repeatedly; `FnMut` may mutate its captures and can be called repeatedly (needs `&mut` to the closure); `FnOnce` may consume its captures and so might be callable only once. They nest: `Fn` ⊂ `FnMut` ⊂ `FnOnce`. A parameter should request the *most permissive* trait its body needs (`FnOnce` if called at most once, then `FnMut`, then `Fn`), because looser bounds accept more closures.

</details>

**Question #3**

Why does this fail to compile, and what one keyword fixes it?

```rust
fn make_greeter(name: String) -> impl Fn() {
    || println!("Hi, {name}")
}
```

<details class="solution">
<summary>Show solution</summary>

The closure borrows `name`, but `name` is a local that's dropped when `make_greeter` returns, so the returned closure would hold a dangling reference (a chapter-9 error). Add `move` before the closure (`move || println!("Hi, {name}")`) so it takes ownership of `name` and can outlive the function.

</details>

You can now pass behavior around as a value. The next lesson ([19.3](https://learnrust.net/chapter-19/the-iterator-trait/)) introduces the other half of the chapter: the `Iterator` trait, the abstraction that closures were really invented to feed.

## Sitemap

See the full [sitemap](https://learnrust.net/sitemap.md) for all pages.
