175

What are the specific conditions for a closure to implement the Fn, FnMut and FnOnce traits?

That is:

  • When does a closure not implement the FnOnce trait?
  • When does a closure not implement the FnMut trait?
  • When does a closure not implement the Fn trait?

For instance, mutating the state of the closure on it's body makes the compiler not implement Fn on it.

ljedrz
  • 17,806
  • 3
  • 63
  • 86
Denilson Amorim
  • 8,822
  • 6
  • 24
  • 31
  • 16
    Have you seen this recent [great article on closures](http://huonw.github.io/blog/2015/05/finding-closure-in-rust/)? – Shepmaster May 11 '15 at 20:50

1 Answers1

186

The traits each represent more and more restrictive properties about closures/functions, indicated by the signatures of their call_... method, and particularly the type of self:

  • FnOnce (self) are functions that can be called once
  • FnMut (&mut self) are functions that can be called if they have &mut access to their environment
  • Fn (&self) are functions that can be called if they only have & access to their environment

A closure |...| ... will automatically implement as many of those as it can.

  • All closures implement FnOnce: a closure that can't be called once doesn't deserve the name. Note that if a closure only implements FnOnce, it can be called only once.
  • Closures that don't move out of their captures implement FnMut, allowing them to be called more than once (if there is unaliased access to the function object).
  • Closures that don't need unique/mutable access to their captures implement Fn, allowing them to be called essentially everywhere.

These restrictions follow directly from the type of self and the "desugaring" of closures into structs; described in my blog post Finding Closure in Rust.

For information on closures, see Closures: Anonymous Functions that Can Capture Their Environment in The Rust Programming Language.

Shepmaster
  • 326,504
  • 69
  • 892
  • 1,159
huon
  • 83,735
  • 17
  • 214
  • 214
  • If a closure only implements `FnOnce`, does this mean that it can be called only once? – nalply May 17 '15 at 18:30
  • @nalply, yes, only once. – huon May 17 '15 at 22:43
  • 11
    I misread nalply's comment and it caused me some confusion. Future readers, please note that he said "if a closure *only* implements `FnOnce`". – sleeparrow Aug 27 '15 at 23:31
  • 2
    Implementation detail: *will automatically implement as many of those as it can.* is not entirely true, it will implement them automatically if it seems to be needed. You can detect a missing Fn-impl for a closure that was used for an FnMut argument using specialization. This is bug https://github.com/rust-lang/rust/issues/26085 – bluss Sep 08 '16 at 17:14
  • 3
    I still struggle to understand how all closures implement `FnOnce` even if they can be called multiple times. The name for this trait is confusing. – Paul Razvan Berg Dec 07 '20 at 10:16
  • 6
    A couple ways to think about it: 1. The "Once" in `FnOnce` refers to an upper bound on how many times the caller will invoke it, not how many times it _can_ be invoked. 2. You can always convert a closure that can be called many times into a closure that can only be called once: simply throw away any memory associated with the closure after the first call. But you can't convert it back the other way. – hjfreyer Dec 30 '20 at 16:42
  • what self are you talking about here? ||{} doesn't have a self. where does the self come from? – nikoss Feb 07 '22 at 16:26
  • @nikoss the `self` of the trait method. It is the struct that contains the captured variables (environment). – huon Feb 08 '22 at 21:22