大家已经注意到,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)); |
} |