|
|
|
@ -591,7 +591,7 @@ fn exec<'a, F: Fn(String) -> ()>(f: F) {
|
|
|
|
|
|
|
|
|
|
#### move 和 Fn
|
|
|
|
|
|
|
|
|
|
在上面,我们讲到了 `move` 关键字对于 `FnOnce` 特征的重要性,但是实际上使用了 `move` 的闭包依然可能实现了 `Fn` 或 `FnMut` 特征。
|
|
|
|
|
在上面,我们讲到了 `move` 关键字对于 `FnOnce` 特征的重要性,但是实际上使用了 `move` 的闭包依然可以使用 `Fn` 或 `FnMut` 特征。
|
|
|
|
|
|
|
|
|
|
因为,**一个闭包实现了哪种 Fn 特征取决于该闭包如何使用被捕获的变量,而不是取决于闭包如何捕获它们**。`move` 本身强调的就是后者,闭包如何捕获变量:
|
|
|
|
|
|
|
|
|
@ -609,9 +609,9 @@ fn exec<F: FnOnce()>(f: F) {
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
我们在上面的闭包中使用了 `move` 关键字,所以我们的闭包捕获了它,但是由于闭包对 `s` 的使用仅仅是不可变借用,因此该闭包实际上**还**实现了 `Fn` 特征。
|
|
|
|
|
我们在上面的闭包中使用了 `move` 关键字,所以我们的闭包捕获了它,但是由于闭包获取了 `s` 的所有权,因此该闭包实现了 `FnOnce` 的特征。
|
|
|
|
|
|
|
|
|
|
细心的读者肯定发现我在上段中使用了一个 `还` 字,这是什么意思呢?因为该闭包不仅仅实现了 `FnOnce` 特征,还实现了 `Fn` 特征,将代码修改成下面这样,依然可以编译:
|
|
|
|
|
但是假如我们将代码修改成下面这样,依然可以编译:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
fn main() {
|
|
|
|
@ -627,6 +627,8 @@ fn exec<F: Fn()>(f: F) {
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
奇怪, 明明是闭包实现的是 `FnOnce` 的特征, 为什么编译器居然允许 `Fn` 特征通过编译呢?
|
|
|
|
|
|
|
|
|
|
#### 三种 Fn 的关系
|
|
|
|
|
|
|
|
|
|
实际上,一个闭包并不仅仅实现某一种 `Fn` 特征,规则如下:
|
|
|
|
|