Читаем Rust by Example полностью

// `to_owned` creates owned data from borrowed one

let mut farewell = "goodbye".to_owned();

// Capture 2 variables: `greeting` by reference and

// `farewell` by value.

let diary = || {

// `greeting` is by reference: requires `Fn`.

println!("I said {}.", greeting);

// Mutation forces `farewell` to be captured by

// mutable reference. Now requires `FnMut`.

farewell.push_str("!!!");

println!("Then I screamed {}.", farewell);

println!("Now I can sleep. zzzzz");

// Manually calling drop forces `farewell` to

// be captured by value. Now requires `FnOnce`.

mem::drop(farewell);

};

// Call the function which applies the closure.

apply(diary);

// `double` satisfies `apply_to_3`'s trait bound

let double = |x| 2 * x;

println!("3 doubled: {}", apply_to_3(double));

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

<p id="see_also_24"><strong><a l:href="#see_also_24">See also:</a></strong></p>

std::mem::drop, Fn, FnMut, Generics, where and FnOnce

<p id="type_anonymity"><strong><a l:href="#type_anonymity">Type anonymity</a></strong></p>

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) 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 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) 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);

}

הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה

Перейти на страницу:

Похожие книги