Rust by Example - страница 27
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: 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
>// `F` must implement `Fn` for a closure which takes no
>// inputs and returns nothing - exactly what is required
>// for `print`.
>fn apply
>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);
>}
>הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Since closures may be used as arguments, you might wonder if the same can be said about functions. And indeed they can! If you declare a function that takes a closure as parameter, then any function that satisfies the trait bound of that closure can be passed as a parameter.
>// Define a function which takes a generic `F` argument
>// bounded by `Fn`, and calls it
>fn call_me
>f();
>}
>// Define a wrapper function satisfying the `Fn` bound
>fn function() {
>println!("I'm a function!");
>}
>fn main() {
>// Define a closure satisfying the `Fn` bound
>let closure = || println!("I'm a closure!");
>call_me(closure);
>call_me(function);
>}
>הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
As an additional note, the Fn, FnMut, and FnOnce traits dictate how a closure captures variables from the enclosing scope.
Closures as input parameters are possible, so returning closures as output parameters should also be possible. However, anonymous closure types are, by definition, unknown, so we have to use impl Trait to return them.
The valid traits for returning a closure are:
• Fn
• FnMut
• FnOnce
Beyond this, the move keyword must be used, which signals that all captures occur by value. This is required because any captures by reference would be dropped as soon as the function exited, leaving invalid references in the closure.
>fn create_fn() -> impl Fn() {
>let text = "Fn".to_owned();
>move || println!("This is a: {}", text)
>}
>fn create_fnmut() -> impl FnMut() {
>let text = "FnMut".to_owned();
>move || println!("This is a: {}", text)
>}
>fn create_fnonce() -> impl FnOnce() {
>let text = "FnOnce".to_owned();
>move || println!("This is a: {}", text)