大家已经注意到,Rust选择无需注解在运行时捕捉变量。这在正常使用时很方便,但是编写函数时,这种模糊性是不允许的。封闭的类型齐全,包括其捕获类型必须注明。捕获封闭使用被注释为以下特征之一的方式:
Fn
: 通过引用以捕获 (&T
)
FnMut
: 通过可变引用需要捕获 (&mut T
)
FnOnce
: 通过值捕获 (T
)
即使是注释,这些都是非常灵活: FnOnce的一个参数指定封闭可以通过T或 &mut T 或 &T在将捕获(如果此举是可能的,任何类型的借还应该是可能的)。 反向并非如此:如果该参数为Fn,那么什么都降低是允许的。因此,规则是:
此外,Rust会优先捕捉,可变通过变量基础变量限制最少的方式:
// A function which takes a closure as an argument and calls // it. The closure takes no input and returns nothing. fn apply(f: F) where F: FnOnce() { // ^ TODO: Try changing this to `Fn` or `FnMut`. f() } // A function which takes a closure and returns an `i32`. fn apply_to_3(f: F) -> i32 where // The closure takes an `i32` and returns an `i32`. F: Fn(i32) -> i32 { f(3) } fn main() { let greeting = "hello"; // A non-copy type. 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`. drop(farewell); }; // Call the function which applies the closure. apply(diary); let double = |x| 2 * x; println!("3 doubled: {}", apply_to_3(double)); }