
13.4 闭包 Pt.4使用闭包捕获环境13.4.0. 写在正文之前Rust语言在设计过程中受到了很多语言的启发而函数式编程对Rust产生了非常显著的影响。函数式编程通常包括通过将函数作为值传递给参数、从其他函数返回它们、将它们分配给变量以供以后执行等等。在本章中我们会讨论 Rust 的一些特性这些特性与许多语言中通常称为函数式的特性相似-闭包本文- 迭代器- 使用闭包和迭代器改进I/O项目- 闭包和迭代器的性能13.4.1. 闭包可以捕获它所在的环境闭包有一项函数所不具备的功能闭包可以访问定义它的作用域内的变量。看个例子fn main() { let x 4; let equal_to_x |z| z x; let y 4; assert!(equal_to_x(y)); }闭包的部分在let equal_to_x |z| z x;这样写有的人可能不太能分清和在这里的作用换一种写法let equal_to_x |z| { z x };也就是说这个闭包的形参是z它会和x也就是4因为上文定义了x 4进行比较返回布尔类型如果相等就是true反之则为false。注意z x后面没有分号如果加了分号这个代码块的返回值就会变成()而不是比较结果。这里闭包直接访问了同在一个作用域的变量x这是函数做不到的。但使用这个特性是有代价的它会产生内存开销。大多数情况下我们不需要它捕获环境更不想产生内存开销所以函数它就不允许从环境中捕获变量而定义和使用函数就永远不会产生这一类型的开销。13.4.2. 闭包从所在环境捕获值的方式闭包通过三种方法来从环境捕获值这三种与函数获得参数的三种方法一样- 取得所有权,其trait名为FnOnceOnce代表一次因为闭包不能多次获取并消耗同一个变量所以它只能被调用一次。- 可变借用,其trait名为FnMut- 不可变借用,其trait名为Fn当程序员在创建闭包时Rust会根据闭包对环境值的使用方式推断出具体应该使用哪个trait- 所有的闭包都实现了FnOnce因为闭包都至少可以被调用一次- 没有移动捕获变量的实现了FnMut- 无需可变访问捕获变量的闭包实现了Fn实际上这三者有包含关系所有实现了Fn的都实现了FnMut所有实现了FnMut的都实现了FnOnce。13.4.3.move关键字在参数列表前使用move关键字可以强制闭包取得它所使用的环境值的所有权。当将闭包传递给新线程以移动数据使其归新线程所有时此方法最为有用。看个例子fn main() { let x vec![1, 2, 3]; let equal_to_x move |z| z x; println!(cant use x here {:?}, x); let y vec![1, 2, 3]; assert!(equal_to_x(y)); }使用了move关键字后x的所有权就移动到了闭包里面后面就用不了x了。13.4.4. 最佳实践当你指定Fntrait bound之一时首先用Fn。基于闭包内的情况如果需要FnOnce或FnMut编译器会再告诉你。