---
title: Iterator 与闭包
url: https://doc.liz6.com/rust/10-standard-library-depth/01-iterator-and-closures
locale: zh
area: rust
tags:
- rust
- 标准库深度
date: 2026-06-30
modified: 2026-06-30
description: Iterator 是 Rust 最成功的抽象——map/filter/chain 等 adaptor 是惰性的(不调用不执行),编译后内联展开为手写循环等效的机器码(zero-cost)。Fn/FnMut/FnOnce 三种闭包 trait 对应三种捕获方式,collect 把迭代器收拢为容器——链式操作从 read…
---

# Iterator 与闭包

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

## Iterator trait: 一切迭代的根源

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

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

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

```rust
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` 请求，`take` 从 `map` 请求，`map` 从 `filter` 请求，`filter` 从 `0..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`

```rust
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*
