Yun Sheng's Site
A Little Bit of This, A Little Bit of That

Rust FnOnce FnMut Fn the 100th Time

tldr

  • FnOnce owns the closure fn call_once(self, args: Args) -> Self::Output
  • FnMut mutable borrows the closure fn call_mut(&mut self, args: Args) -> Self::Output
  • Fn borrows the closure fn call(&self, args: Args) -> Self::Output
  • Fn implements FnMut, FnMut implements FnOnce
  • FnOnce has less restrictions where Fn has most restrictions
  • Rust checks your anonymous function to deduce which call traits to implement
  • let f = move || {println!("{}", copy_type);}; for a Copy type would copy and own it. The original variable is not owned by f
  • closure could be borrowed, but it may or may not be callable.
    • FnOnce calling requires ownership
    • FnMut callable through a mutable borrow
    • Fn callable through a shared borrow

Overview

I was on the subway and thinking about FnOnce, FnMut, Fn for the 100th time and it was not crystal clear for me (again).

So I decided to actually learn it again but this time write it down.

The Need To Pass In a Function

Ever since functions became first class citizens in most programming languages, passing in a function to another function is more of a standard thing now.

Examples like setTimeout takes in a function and that function would be called when the timeout timed out (roughly)

Sometimes you would create a function on the fly to pass to another function. And you probably heard of this thing called closure many times, but what is a closure?

What Is a Closure (In My Mind)

A closure is an abstraction representing your function and the captured environment when the function was created. A good mental model is to envision a struct holding your function logic and the captured environment by either value or reference.

1
2
3
4
5
6
7
8
9
func main() {
    x := 10

    f := func() int {
        return x
    }

    fmt.Println(f())
}

In the function above we created f inside main and called f().

If you look closer you would notice that f refers to x.

When f() was running it somehow knows information about x. Running this program would print 10.

The reason why f() knows about x is because when f was created the programming language had support to let it “capture” the surrounding environment. Closure is the anonymous function and the environment enclosing it.

Note that the way f captures the environment might be different, it could capture by value, or it could capture by reference.

If we add a few more lines to the example above it suddenly becomes less straight forward.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func main() {
    x := 10

    f := func() int {
        return x
    }

    fmt.Println(f())

    x += 1
    fmt.Println(f()) // 10 or 11?
}

The second f() call would print 10 if f captured x by value, it would print 11 if f captured x by reference.

In this specific example it is printing 11 because x is captured by reference.

In Go, in order to let f capture x by value you would need to capture it by value by adding a parameter to f

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
func main() {
	x := 10

	// I could have used `func(x int) func() int` as signature
	// But just to reduce confusion I used `xx int`
	f := func(xx int) func() int {
		return func() int {
			return xx
		}
	}

	f1 := f(x)

	fmt.Println(f1())

    x += 1
	fmt.Println(f1()) // now prints 10
}

The above f now takes in x and returns a function. And we created f1 which captures x by value when x was 10.

From FnOnce, FnMut and Fn’s Point of View

Hopefully the closure crash course makes sense. Now let’s go back to Rust. FnOnce, FnMut and Fn are traits, and rust closures would implement these traits.

Difference On What Happens When They Are Called

Imagine when Rust creates an anonymous function it creates a struct and that struct implements one or more of these traits. This struct is the closure.

  • FnOnce’s call_once would consume the closure. Meaning it takes in self
  • FnMut’s call_mut would mutably borrow the closure. Meaning it takes in &mut self
  • Fn’s call would borrow the closure. Meaning it takes in &self

It might be a bit more clear to see this by checking the trait required method.

  • FnOnce requires fn call_once(self, args: Args) -> Self::Output
  • FnMut requires fn call_mut(&mut self, args: Args) -> Self::Output
  • Fn requires fn call(&self, args: Args) -> Self::Output

Difference On What Guarantees They Provide

Now we know FnOnce, FnMut and Fn accesses the closure differently when called. With that in mind we could understand the following better.

FnOnce Alone Only Guarantees At Most Once Call

So we know that when calling a FnOnce it consumes the closure. This means it could technically drop things in the closure when it’s being called. This means it is only safe to call FnOnce at most one time.

FnMut Can Be Called Multiple Times But Might Change Things

On the other hand, we know that calling FnMut mutable borrows it’s closure by &mut self, meaning this is a mutable borrow. All restrictions of a mutable borrow in Rust stands.

Fn Can Be Called Multiple Times

And for Fn we know it just borrows the closure so it can be called as much as possible.

Relations Between These Three

Turns out there is a relation between these three.

Fn implements FnMut and FnMut implements FnOnce.

In terms of inheritance this means

Fn inherits FnMut inherits FnOnce

So FnOnce is like the base class, and FnMut is the sub class of FnOnce and Fn is the sub class of FnMut

Kinda like, “Rectangle(Fn) inherits Square(FnMut) inherits Shape(FnOnce)”

Which means, wherever you need an FnOnce you could pass in a FnMut or a Fn.

I found it harder to remember/understand if I try to use the base class sub class mentality.

It feels more natural for me to think in the following way.

  • FnOnce only implements call_once.
  • FnMut implements call_once and on top of that it implements call_mut
  • Fn implements call_once and call_mut and on top of that it implements call

So FnOnce implements 1 method, FnMut implements an additional one on top of FnOnce, Fn implements an additional one on top of FnMut.

This means where ever a FnOnce is needed, I can pass in an FnOnce or FnMut or Fn

From The Function’s Point of View

So far I’ve been viewing things from the traits point of view. But there is another view that is also important. The view as a function writer who needs to take in closures.

Before we go there let’s look at this interesting quote from the one and only Hongwei Xi.

The Weaker The Parameter, The Stronger The Function, Vice Versa

Functions has parameters, and we could use types to limit the parameter.

For instance we could have a function adding two integers func Add(a int, b int). The parameter is more restrictive (strong), so the function doesn’t need to handle much.

On the other hand, if you have func Add(a any, b any), the parameter is loose (it literally says any). So the function itself needs to handle more cases (more possibilities could be thrown to the function).

One example to think of is in python, the print() function is very strong

So Among FnOnce, FnMut and Fn, Who Is Strong And Who Is Weak?

So who is the stronger one among the three when trying to use them as a function designer?

The answer is Fn is the most restrictive (strong) one and FnOnce is the loose one (weak).

So when you design a function like fn foo(f: impl FnOnce() -> String) you are saying: give me a function that I could call, and I can get by by only calling this function once (if you think about this, it’s kinda the bare minimum you could ask for a function)

Where as if you do fn foo(f: impl Fn()), you are asking for a function that could be called multiple times through a shared reference.

Rust Tries To Find Out What Your Closure Actually Is Doing

One thing that confused me for a long time is in Rust the compiler actually goes through your anonymous function and tells if your function needs to own/mut borrow/borrow variables in the closure.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
fn main() {
    // (1) borrow non copy type
    // type of f is Fn
    let s = String::from("yo");
    let f = || {
        println!("{}", s); // rust knows you are only borrowing, so f is of type Fn
    };

    // (2) mutable borrow non copy type
    // type of f is FnMut
    let mut s1 = String::from("sup");
    let f = || {
        s1.push_str(" bro");
        println!("{}", s1);
    };

    // (3) own non copy type
    // type of f is FnOnce
    let s3 = String::from("wassup");
    let f = || {
        drop(s3);
    };

    // (4) borrow Copy type
    // type of f is Fn
    let x = 7;
    let f = || {
        println!("{}", x);
    };

    // (5) mutable borrow Copy type
    // type of f is FnMut
    let mut x2 = 7;
    let f = || {
        x2 += 1;
        println!("{}", x2);
    };

    // (6) own Copy type
    // type of f is Fn
    let x3 = 7;
    let f = move || {
        // note that even forcing a move here it's still copied.
        println!("{}", x3);
    };
}

Some notes for each case

  • (1) Rust saw f only needs to borrow s, type of f is Fn.
  • (2) Rust saw the push_str() and calls closure with &mut self, type of f is FnMut.
  • (3) Rust saw drop(s3), calls closure with self, type of f is FnOnce. Note that I did not force a move with let f = move || {}.
  • (4) Similar to (1), the difference is type of x is i32 and it implements Copy. Type of f is Fn.
  • (5) Similar to (2), Type of f if FnMut.
  • (6) Here is the most different one, not in terms of the type of f but in terms of what happens to x3. Here type of f is Fn, I tried to force f own x3 by using move. But because i32 implements Copy, a copy of x3 is actually copied in and owned by f. Meaning f does not actually own the x3 outside, it owns a copy of x3 inside.

FnOnce, FnMut and Fn Could Be Passed By Reference

It is possible to borrow Fn, FnMut, FnOnce. But then can we still call them?

Let’s have a look at the following which demonstrates what I meant by “possible to borrow”.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
fn main() {
    let s = String::from("yo");
    // f is of type FnOnce
    let f = || {
        drop(s);
    };

    // borrow is of type `& impl FnOnce()`
    let borrow = &f;
    borrow(); // error here
}

Here borrow is of type & impl FnOnce(). Turns out you can not call this closure through a borrow. It kinda makes sense, because there could be multiple borrows, and since calling FnOnce consumes the closure, it can not be called through a borrow.

After understanding the above, the following two would be easier to understand. FnMut can only be called through a mutable borrow because calling FnMut might mutate the closure so you could only call it via a mutable borrow.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
fn main() {
    let mut s = String::from("yo");
    // f is of type FnMut
    let mut f = || {
        s.push_str("sup");
    };

    // borrow is of type `&mut impl FnMut()`
    let borrow = &mut f;

    // all calls good
    borrow();
    borrow();
}

Then the Fn case is the most simple one, you can call Fn through a normal borrow relatively.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
fn main() {
    let x = 7;
    // f is of type Fn
    let f = || {
        println!("{}", x);
    };

    // borrow is of type `& impl Fn()`
    let borrow = &f;

    // all calls good
    borrow();
    borrow();
}

To summary, a closure implementing FnOnce only can’t be called through any borrow, a closure implementing FnMut but not Fn can only be called through a mutable borrow, and Fn could be called through any borrow.

Closure &closure callable? &mut closure callable?
FnOnce only No No
FnMut but not Fn No Yes, repeatedly
Fn Yes, repeatedly Yes, repeatedly
Update: 2026-10-21

See Also