对 Rust 闭包的个人理解总结
January 26, 2020
把它拆解为两个独立对象来帮助理解:变量,闭包。
变量有没有发生所有权转移,将决定这个变量还能否在闭包外部使用,但不决定这个闭包能调用多少次,只决定变量的使用范围。
- 所有权转移,只对引用类型有效,复制类型不会发生所有权转移
- 没有转移,闭包外部还可以访问这个变量 (所以复制类型永远可以在闭包外访问)
- 转移,只有闭包内部能访问这个变量
-
转移分隐式和显式
- 显式用 move 关键字
- 隐式,不使用 move,但在闭包内消耗了外部变量,即 drop
闭包内部对捕获变量的使用方式,将决定这个闭包能否调用多次。
- 如果闭包对变量是只读,则闭包是 Fn 类型,可调用多次
- 如果闭包对变量进行修改,则闭包是 FnMut 类型,可调用多次
- 如果闭包对变量进行了 drop,则闭包是 FnOnce 类型,只可调用一次
所有权转移跟 FnOnce 的关系:
- 发生所有权转移,闭包可以是 Fn/FnMut/FnOnce
- 闭包是 FnOnce 类型,则一定发生所有权转移
move 和 FnOnce 是互斥的:
- 需要显示用 move,说明闭包里并没有 drop 掉捕获的变量,因此闭包必须不是 FnOnce
- FnOnce drop 了变量,必须发生了所有权转移,并不需要显式地使用 move
举例说明。
例子一,闭包对某个引用类型的变量进行捕获,在闭包里只对这个变量进行了只读访问,捕获时使用了 move。则:
- 变量所有权转移到了闭包内部,闭包外部不再可以访问
- 闭包是 Fn 类型,可以访问多次
例子二,闭包捕获多个引用类型的变量,分别是 a, b, c,闭包内部对 a 只读,对 b 修改,对 c drop。则:
- 闭包本身是 FnOnce,只能调用一次
- a, b 所有权没有转移,还可以继续在闭包外访问
- c 所有权转移,不能在闭包外访问
(TODO: Code example)