在Rust中,整个标准集合库基于迭代器的概念。迭代器是一个实现了Iterator特征的对象,在其中定义了next()方法。该方法返回数据序列的下一个元素(Option<T>,其中Some(T)是下一个值,None表示序列结束)。
标准迭代器示例:
let v = vec![1, 2, 3]; let mut iter = v.iter(); while let Some(x) = iter.next() { println!("{}", x); }
迭代器适配器是一些方法(例如,.map()、.filter()、.enumerate()、.take()),返回新的迭代器,根据传入的函数“即时”处理值。
自定义迭代器通过创建一个结构体并为其实现Iterator特征与自定义行为来实现:
struct Counter { count: u8 } impl Iterator for Counter { type Item = u8; fn next(&mut self) -> Option<Self::Item> { if self.count < 5 { self.count += 1; Some(self.count) } else { None } } }
当标准适配器足以处理集合时,使用标准适配器即可。需要实现自定义迭代器的情况包括:
可以创建无限迭代器吗?如果尝试通过
.collect()将其收集到集合中,会发生什么?
答案: 是的,在Rust中创建了类似于std::iter::repeat的迭代器,它返回无限序列:
let mut endless = std::iter::repeat(1); endless.next(); // 将无限返回Some(1)
如果尝试通过.collect()将这样的迭代器收集到集合中,程序会挂起或因内存溢出而崩溃,因为迭代不会自行结束!
故事
在REST API项目中,对1000个元素的数组进行了排序,然后使用.iter().filter(|x| *x > 500),但在复杂适配器内采用了.fold(0, |acc, _| acc + 1)而不是.collect::<Vec<_>>(),因此失去了对迭代是否会正确结束的理解。结果:由于迭代器的无界懒惰过滤而导致的随机挂起。
故事
在一个专有引擎中,负责生成唯一ID的随机开发者决定实现自己的迭代器,却忘记在达到限制时返回None。结果,迭代进入无限循环,生产环境中的服务器消耗了全部的CPU并无法响应请求。
故事
在前端部分(WebAssembly模块)中,使用了具有嵌套适配器的迭代器:.map().filter().skip(),并尝试通过.collect()为表单获取结果。在转换适配器的类型时,Rust在编译时发出复杂的类型不匹配错误,因为忘记指定准确的集合类型:.collect::<Vec<_>>()。问题通过添加注释解决了,但花费了几个小时寻找原因。