闭包与迭代器

闭包

闭包是可以保存在变量中或作为参数传递给其他函数的匿名函数。闭包会捕获其环境。

闭包类型推断和注解

闭包通常不要求像函数一样对参数与返回值进行类型注解。闭包通常较短并与特定上下文相关,而不适用于任意情景。

#![allow(unused)]
fn main() {
    // 完整函数展示
    fn add_one_v1(x: u32) -> u32 {
        x + 1
    }
    // 完整标注闭包定义
    let add_one_v2 = |x: u32| -> u32 { x + 1 };
    // 省略类型注解
    let add_one_v3 = |x| {x + 1};
    // 省略大括号
    let add_one_v4 = |x| x + 1;
    // 调用 v3 v4 是代码能编译的必要条件,否则无法推断类型。
    add_one_v3(1);
    add_one_v4(1);
}

捕获引用或移动所有权

闭包可以通过三种方式捕获其环境中的值,它们直接对应到函数获取参数的三种方式:不可变借用、可变借用和获取所有权。闭包将根据函数体中对捕获值的操作来决定使用哪种方式。

将被捕获的值移出闭包和 Fn trait

一旦闭包捕获了定义它的环境中的某个值的引用或所有权(也就影响了什么会被移 进 闭包, 如有),闭包体中的代码则决定了在稍后执行闭包时,这些引用或值将如何处理(也就影响了 什么会被移 出 闭包,如有)。闭包体可以执行以下任一操作:将一个捕获的值移出闭包,修改 捕获的值,既不移动也不修改值,或者一开始就不从环境中捕获任何值。

闭包捕获和处理环境中的值的方式会影响闭包实现哪些 trait,而 trait 是函数和结构体指定它 们可以使用哪些类型闭包的方式。根据闭包体如何处理这些值,闭包会自动、渐进地实现一 个、两个或全部三个 Fn trait。

  1. FnOnce 适用于只能被调用一次的闭包。所有闭包至少都实现了这个 trait,因为所有闭包都 能被调用。一个会将捕获的值从闭包体中移出的闭包只会实现 FnOnce trait,而不会实现其 他 Fn 相关的 trait,因为它只能被调用一次。
  2. FnMut 适用于不会将捕获的值移出闭包体,但可能会修改捕获值的闭包。这类闭包可以被 调用多次。
  3. Fn 适用于既不将捕获的值移出闭包体,也不修改捕获值的闭包,同时也包括不从环境中捕 获任何值的闭包。这类闭包可以被多次调用而不会改变其环境,这在会多次并发调用闭包 的场景中十分重要。

迭代器

迭代器模式允许你依次对一个序列中的项执行某些操作。迭代器(iterator)负责遍历序列中 的每一项并确定序列何时结束的逻辑。使用迭代器时,你无需自己重新实现这些逻辑。Rust 中迭代器是 惰性的。

#![allow(unused)]
fn main() {
pub trait Iterator {
    type Item; // 关联类型
    fn next(&mut self) -> Option<Self::Item>; // 获取下一个元素
}

}

消费迭代器的方法

一些方法在定义中调用了 next 方法,这些调用 next 的方法被称为消费者适配器。

迭代器适配器

他们不会消耗迭代器而是通过改变原始迭代器的某些方面生成不通的迭代器。