自定义迭代器
你会学到什么
- 实现
Iteratortrait 只需要写一个next方法。 - 一旦实现,就能免费用上
map、filter、sum等所有适配器。 - 关联类型
type Item指定每次产出的值的类型。
最小示例
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.current < self.max {
self.current += 1;
Some(self.current)
} else {
None
}
}
}
运行代码
cd examples
cargo run -p rt_21_custom_iterator
cargo test -p rt_21_custom_iterator
代码讲解
next 返回 Some(item) 表示还有值,返回 None 表示结束。其余适配器方法都是基于 next 的默认实现,所以你的类型立刻就能:
let total: u32 = Counter::new(5).sum();
let doubled: Vec<u32> = Counter::new(3).map(|v| v * 2).collect();
for value in Counter::new(3) { /* ... */ }
实现了 Iterator 的类型可以直接用在 for 循环里,因为 for 本质就是反复调用 next。
常见错误
next 忘了推进状态,导致无限循环:
fn next(&mut self) -> Option<u32> {
Some(self.current) // ❌ 永远不结束
}
确保每次调用都改变状态并最终返回 None。
练习
- 实现一个产出斐波那契数列前 n 项的迭代器。
- 给
Counter加一个起始值,从start数到max。
小结
实现 Iterator 只需一个 next,就能接入整个迭代器生态,这是 Rust “小接口、大复用”的典型例子。
下一步
接下来进入智能指针,学习 Box、Rc 和 RefCell。
完整示例代码
下面是 examples/21_custom_iterator/ 的完整源码。无需 clone 仓库,直接在页面上阅读、复制、对照运行。
examples/21_custom_iterator/src/main.rs
//! 通过实现 Iterator trait 创建自定义迭代器。
/// 从 1 数到 max(含)的计数器。
struct Counter {
current: u32,
max: u32,
}
impl Counter {
fn new(max: u32) -> Self {
Self { current: 0, max }
}
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.current < self.max {
self.current += 1;
Some(self.current)
} else {
None
}
}
}
fn main() {
// 自定义迭代器自动获得所有适配器方法。
let total: u32 = Counter::new(5).sum();
println!("sum 1..=5 = {total}");
let doubled: Vec<u32> = Counter::new(3).map(|value| value * 2).collect();
println!("doubled = {doubled:?}");
for value in Counter::new(3) {
println!("count = {value}");
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn yields_sequence() {
let values: Vec<u32> = Counter::new(3).collect();
assert_eq!(values, vec![1, 2, 3]);
}
#[test]
fn empty_when_zero() {
let values: Vec<u32> = Counter::new(0).collect();
assert!(values.is_empty());
}
#[test]
fn composes_with_adapters() {
let total: u32 = Counter::new(4).filter(|value| value % 2 == 0).sum();
assert_eq!(total, 6);
}
} examples/21_custom_iterator/Cargo.toml
[package]
name = "rt_21_custom_iterator"
version.workspace = true
edition.workspace = true
publish.workspace = true