Type anonymity need Generics
- A closure is essentially an anonymous struct
- A function that accepts a closure parameter only needs to restrict the parameter to implement the following traits:
- Fn
- FnMut
- FnOnce
Closures succinctly capture variables from enclosing scopes. Does this have any consequences?
It surely does.
Observe how using a closure as a function parameter requires generics, which is necessary because of how they are defined:
#![allow(unused)] fn main() { // `F` must be generic. fn apply<F>(f: F) where F: FnOnce() { f(); } }
When a closure is defined, the compiler implicitly creates a new
anonymous structure to store the captured variables inside, meanwhile
implementing the functionality via one of the traits
: Fn
, FnMut
, or
FnOnce
for this unknown type.
This type is assigned to the variable which is stored until calling.
Since this new type is of unknown type, any usage in a function will require generics.
However, an unbounded type parameter
<T>
would still be ambiguous and not be allowed.
Thus, bounding by one of the traits: Fn, FnMut, or FnOnce (which it implements) is sufficient to specify its type.
// `F` must implement `Fn` for a closure which takes no // inputs and returns nothing - exactly what is required // for `print`. fn apply<F>(f: F) where F: Fn() { f(); } fn main() { let x = 7; // Capture `x` into an anonymous type and implement // `Fn` for it. Store it in `print`. let print = || println!("{}", x); apply(print); }
This example could be compared with the decrator mode
See also:
A thorough analysis, Fn
, FnMut
,
and FnOnce