本页目录

Iterator 与闭包

Iterator 是 Rust 最成功的抽象——map/filter/chain 等 adaptor 是惰性的(不调用不执行),编译后内联展开为手写循环等效的机器码(zero-cost)。Fn/FnMut/FnOnce 三种闭包 trait 对应三种捕获方式,collect 把迭代器收拢为容器——链式操作从 readable 到 zero-cost 一步到位。

Iterator trait: 一切迭代的根源

pub trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
    // 70+ 方法有默认实现 — 它们全部基于 next()
}

next() 是唯一必须实现的方法。所有其他方法——map, filter, take, fold, collect——都是基于 next() 的默认实现。这意味着只要实现 next(),你的类型自动获得整个迭代器生态。

Lazy Evaluation: 迭代器不做任何事,直到被"驱动"

let v: Vec<i32> = (0..10)
    .filter(|x| x % 2 == 0)         // 不发生 — 只是构建链
    .map(|x| x * 2)                  // 不发生
    .take(3)                         // 不发生
    .collect();                      // 现在! 所有 adaptors 被"驱动"
// → [0, 4, 8]

这段代码在 collect() 之前不会处理任何一个元素。当 collect() 调用 next() 时,它从 take 请求,takemap 请求,mapfilter 请求,filter0..10 请求——形成一条"拉"链。这与 eager evaluation(如 Python list comprehension)有根本区别。

关键 Adaptors

adaptor作用何时触发
map转换每个元素lazy
filter保留满足条件的lazy
take(n)取前 n 个后停止lazy
skip(n)跳过前 n 个lazy
enumerate附加索引 (index, item)lazy
chain拼接两个迭代器lazy
flat_map每个元素展开为迭代器lazy
fold累积 (reduce)eager (消耗迭代器)
collect收集为集合eager

三种闭包 Trait: FnOnce → FnMut → Fn

这三个 trait 形成一条约束链:

FnOnce: 只能调用一次 — consume 捕获的值 (ownership 转移)
FnMut:  `&mut self` — 可以修改捕获的值, 可以多次调用
Fn:     `&self` — 只读捕获, 可以多次调用, 最通用
  • 所有闭包默认实现 FnOnce
  • 如果闭包不 consume 捕获的值 → 也实现 FnMut
  • 如果闭包不修改捕获的值 → 也实现 Fn
let s = String::from("hi");
let f = || s;                        // s 被 move 进闭包 — 这是一个 FnOnce
// f() 只能调用一次 — 调用后 s 被 consume, f 不能再被调用

let mut v = vec![1, 2, 3];
let mut f = || { v.push(4); };       // 修改 v — FnMut (can call multiple times)

let x = 42;
let f = || println!("{}", x);        // 只读 — Fn (most general)

零成本迭代

release 模式下,迭代器链通常被编译器"融合"为单个循环——map, filter, collect 的连续调用被优化为等价的 for loop,没有额外分配,没有虚函数调用。这就是 Rust 的 zero-cost abstraction 在迭代器上的体现。

参考

  • Rust Book: Chapter 13
  • Rust Reference: Fn traits, Iterator

Keywords: Iterator, lazy evaluation, collect, Fn, FnMut, FnOnce, adaptor, zero-cost