自定义迭代器
实现 Iterator
自定义迭代器 是 CoddyKit 上的免费 Learn Rust Coding 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Learn Rust Coding 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Learn Rust Coding 课程共包含 4 节课。
创建您自己的迭代器
您不受限于内置迭代器。通过为自己的类型实现 Iterator 特征,它就能免费获得所有适配器和消费者。
您只需提供 Item 类型和一个 next 方法。
Counter 结构体
先创建一个保存迭代器状态的结构体。简单的计数器只需要一个当前值。
struct Counter {
count: u32,
}
fn main() {
let c = Counter { count: 0 };
println!("start at {}", c.count);
}实现 next
为该结构体实现 Iterator。设置 type Item,然后编写 next 来推进状态:在达到停止条件之前返回 Some,之后返回 None。
struct Counter { count: u32 }
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.count < 5 {
self.count += 1;
Some(self.count)
} else {
None
}
}
}
fn main() {
let mut c = Counter { count: 0 };
println!("{:?}", c.next());
println!("{:?}", c.next());
}在 for 循环中使用
一旦存在 next,您的类型就可以像任何标准迭代器一样在 for 循环中使用。
struct Counter { count: u32 }
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.count < 5 { self.count += 1; Some(self.count) } else { None }
}
}
fn main() {
for n in (Counter { count: 0 }) {
print!("{} ", n);
}
println!();
}免费获得适配器和消费者
由于您只实现了一个方法,整个迭代器工具箱现在都可以使用了。这里我们将配对的计数器值求平方后再求和。
struct Counter { count: u32 }
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.count < 5 { self.count += 1; Some(self.count) } else { None }
}
}
fn main() {
let total: u32 = Counter { count: 0 }.map(|x| x * 2).sum();
println!("{}", total);
}构造函数方法
添加一个 new 函数,这样用户就不必直接操作内部字段。这种方式更加整洁,也能让您将字段保持为私有。
struct Counter { count: u32 }
impl Counter {
fn new() -> Counter { Counter { count: 0 } }
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.count < 3 { self.count += 1; Some(self.count) } else { None }
}
}
fn main() {
let v: Vec<u32> = Counter::new().collect();
println!("{:?}", v);
}Fibonacci 迭代器
迭代器可以携带更丰富的状态。Fibonacci 生成器会保存最后两个值,并在每次调用 next 时更新它们。
struct Fib { a: u64, b: u64 }
impl Iterator for Fib {
type Item = u64;
fn next(&mut self) -> Option<u64> {
let current = self.a;
self.a = self.b;
self.b = current + self.b;
Some(current)
}
}
fn main() {
let fib = Fib { a: 0, b: 1 };
let seq: Vec<u64> = fib.take(8).collect();
println!("{:?}", seq);
}无限迭代器也没问题
Fibonacci 迭代器永远不会返回 None——它是无限的。这是安全的,因为惰性求值意味着只有在需要时才会生成值。使用 take 可以限制它的长度。
struct Fib { a: u64, b: u64 }
impl Iterator for Fib {
type Item = u64;
fn next(&mut self) -> Option<u64> {
let c = self.a;
self.a = self.b;
self.b = c + self.b;
Some(c)
}
}
fn main() {
let big = Fib { a: 0, b: 1 }.nth(20);
println!("{:?}", big);
}遍历包装类型
您经常会在一个借用数据的辅助结构体上实现 Iterator。这里,一个步进器会从内部存储的范围中每隔一个数字生成一个值。
struct EvenUpTo { current: u32, max: u32 }
impl Iterator for EvenUpTo {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.current > self.max { return None; }
let value = self.current;
self.current += 2;
Some(value)
}
}
fn main() {
let evens: Vec<u32> = (EvenUpTo { current: 0, max: 10 }).collect();
println!("{:?}", evens);
}为何要构建自定义迭代器
自定义迭代器可以让您在不分配完整集合的情况下流式生成值,表示无限或计算得出的序列,并为调用者提供熟悉且可组合的接口。
一个小小的 next 方法就能解锁整个生态系统。
设计建议
让状态保持精简,在结束时恰好返回一次 None(无限迭代器则永不返回),并避免在 next 中执行繁重操作,以便让惰性求值保持轻量。
快速检查
实现迭代器特征。
回顾
您已经构建了自定义迭代器:
- 在结构体中保存状态,然后实现
impl Iterator - 定义
type Item并编写next - 立即免费获得适配器和消费者
- 迭代器可以是有限的,也可以是无限的;使用
take限制无限迭代器
常见问题解答
「自定义迭代器」课时是免费的吗?
是的 — 「自定义迭代器」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Learn Rust Coding 课程的其余内容,请升级到 CoddyKit PRO。 Learn Rust Coding 课程共包含 4 节课。
「自定义迭代器」这节课中我会学到什么?
实现 Iterator 你通过在浏览器中直接运行的动手代码来练习 Learn Rust Coding,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Learn Rust Coding 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Learn Rust Coding 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「自定义迭代器」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Learn Rust Coding 课中编写并运行代码吗?
能。每节 Learn Rust Coding 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。