book
book copied to clipboard
CHP13: Closures
The section that talks about what traits closures get mapped to, in chapter 13, is a little confusing. See the highlights sentences below.
These are encoded in the three Fn traits as follows:
- FnOnce consumes the variables it captures from its enclosing scope, known as the closure’s environment. To consume the captured variables, the closure must take ownership of these variables and move them into the closure when it is defined. The
Once part of the name represents the fact that the closure can’t take ownership of the same variables more than once, so it can be called only once.- FnMut can change the environment because it mutably borrows values.
- Fn borrows values from the environment immutably.
When you create a closure, Rust infers which trait to use based on how the closure uses the values from the environment.
All closures implement FnOnce because they can all be called at least once.
The definition of FnOnce says that closures that implement this trait can be called only once, but the paragraph below the definition says that "All closures implement FnOnce because they can all be called at least once.
I don't know if I'm missing something or not reading in between the lines well enough, but this is confusing. Which is it? Only once, or at least once?
Think of it this way: if you can call something 20 times, you can call something 1 time, because 1 is less than 20. By the same way, if you have a function that says "I can only call this closure one time!" and you pass it a closure that can be called 20 times, that's totally okay.
Closures will automatically implement one, two, or all three of these Fn traits, in an additive fashion:
- FnOnce applies to closures that can be called at least once.
I just spotted this too and was really confused when reading it.
Actually, the whole Moving Captured Values Out of the Closure and the Fn Traits section is very confusing.
I think what the author meant to expose was the covariance Fn: FnMut: FnOnce, but the way it's presented is not clear. Stating that "FnOnce applies to closures that can be called at least once." feels just wrong to me and directly contradicts the definition of FnOnce. Maybe the author meant "FnOnce is applied to closures that may be called at least once"? The model form of the 2nd branch is strange too, maybe the author meant "may" and not "might". And there, the text doesn't say "that may not mutate the capture values" but the opposite, so it's not the same reasoning.
Or maybe the meaning was:
FnOnceis implemented by all closures,FnMutis implemented by all closures that can be called more than once (because they don't move captured values),Fnis implemented by all closures that can be called more than once concurrently (because they don't move or mutate captured values).
This is followed by an example where the trait is a requirement, and not something automatically applied to a closure, which doesn't help understand the meaning of the section.
Anyway, my take-away is
- closures can be either
Fn,FnMutorFnOncedepending on what they do with their environment; - it must be compatible with the requirement of the code using them;
- thanks to covariance we can use for example a closure with the
Fntrait with code that requires anFnOncetrait.