Baurine's Blog

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


Comments