14.1 闭包:捕获环境的匿名函数
14.1.1 闭包会捕获其环境
14.1.2 闭包类型推断和注解
- 闭包并不总是要求像
fn
函数那样在参数和返回值上注明类型 - 闭包通常很短,并只关联于小范围的上下文而非任意情境
- 如果尝试对同一闭包使用不同类型则就会得到类型错误!
14.1.3 捕获引用或者移动所有权
- 闭包可以有3种参数捕获方式:1、不可变借用;2、可变借用;3、获取所有权
- 对于不可变借用:可多处使用(如:打印)
- 对于可变借用:在闭包定义和调用之间不能有不可变引用来使用(如:打印)!
- 对于获取所有权:可使用
move
关键字来强制闭包获取它用到的环境中值的所有权
14.1.4 将被捕获的值移出闭包和 Fn trait
- 闭包可以做3种事:1、将一个捕获的值移出闭包;2、修改捕获的值,但不移出闭包;3、既不移动也不修改值,或者一开始就不从环境中捕获值。与之对应的,闭包取决于应用场景可以实现下面3种 trait(可同时实现多个 trait)
FnOnce
:适用于能被调用一次的闭包,所有闭包都至少实现了这个 trait,因为所有闭包都能被调用。一个会将捕获的值移出闭包体的闭包只实现FnOnce
trait,这是因为它只能被调用一次(比如:xxx_vec.push(value)
将会移出value
的所有权给到闭包外部的向量xxx_vec
,因此该闭包就会被实现为一个FnOnce
闭包)FnMut
:适用于不会将捕获的值移出闭包体的闭包,但它可能会修改被捕获的值。这类闭包可以被调用多次(==闭包内部可以做一些其他的计算操作 或者说 修改值,但这些操作不能返回值 或者说 不能将值移出闭包体,比如示例13-9所示的操作:num_sort_operations += 1;
==)Fn
:适用于既不将被捕获的值移出闭包体也不修改被捕获的值的闭包,当然也包括不从环境中捕获值的闭包。这类闭包可以被调用多次而不改变它们的环境,这在会多次并发调用闭包的场景中十分重要- 注意:上面这些 trait 会根据代码的实现方式来自动对应!!!
14.2 迭代器:处理元素序列
14.2.1 Rust 的迭代器
- 在 Rust 中,迭代器是 惰性的(lazy),这意味着在调用方法使用迭代器之前它都不会有效果
14.2.2 Iterator trait 和 next 方法
Iterator
trait 要求同时定义一个 Item 类型,这个 Item 类型被用作next
方法的返回值类型- 迭代器的消费(重要概念):在迭代器上调用
next
方法改变了迭代器中用来记录序列位置的状态,每调用一次next
都会从迭代器中消费(去掉)一个项 iter
:调用中得到的值是不可变引用iter_mut
:调用中得到的值是可变引用into_iter
:获取所有权并返回拥有所有权的迭代器
14.2.3 消费适配器:调用 next 方法会消费迭代器
- 迭代器的消费(重要概念):在迭代器上调用
next
方法改变了迭代器中用来记录序列位置的状态,每调用一次next
都会从迭代器中消费(去掉)一个项 - 调用
next
方法的方法被称为 消费适配器(consuming adaptors),因为调用这些方法会获取迭代器的所有权并反复调用next
来遍历迭代器(也就是会消耗迭代器)
14.2.4 迭代适配器:改变迭代器类型
- Iterator trait 中定义了另一类方法,被称为 迭代器适配器(iterator adaptors),他们不消耗迭代器,而是将当前迭代器变为不同功能的迭代器(如:通过
map
方法来转换一个迭代器) - 可以链式调用多个迭代器适配器。不过因为所有的迭代器都是惰性的,必须调用一个消费适配器方法以便获取迭代器适配器调用的结果(如:
collect()
方法)!
14.2.5 使用闭包来获取上下文环境
filter
:判断一个使用迭代器的每一个项并返回布尔值的闭包,如果闭包返回 true,其值将会包含在filter
提供的新迭代器中。如果闭包返回 false,其值不会包含在结果迭代器中
14.2.6 实现 Iterator trait 来创建自定义迭代器
14.3 改进 I/O 项目
14.3.1 使用迭代器并去掉 clone
14.3.2 使用迭代适配器来使代码更简明
14.4 性能对比:循环 VS 迭代器