21-迭代器
7.4 迭代器
在第1章中我们对迭代器已经有了一些了解。重申一下,迭代器兼容任意普通类型,可以通过以下3种方式遍历集合类型中的元素:self、&self及&mut self。它们并非新概念,诸如C++和Python这类主流语言也包含类似的概念,它们起初看起来会让人感到惊讶,因为它们的存在形式是某种关联类型特征。在Rust中,处理集合类型时经常会用到迭代器。
为了了解它的工作机制,让我们来看一看std::iter模块中的Iterator特征定义:
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
// 省略了其他默认方法
}
Iterator特征是一个关联类型特征,它要求为任何实现的类型定义两个元素。第1个是关联类型Item,它指定了迭代器产生的元素。第2个是next方法,每当我们需要从迭代的类型中读取一个值时会调用它。在这里我们省略了其他方法,因为它们具有默认实现。要让类型支持迭代,我们只需指定Item类型,并实现next方法。其他所有具有默认实现的方法都可用于该类型。这种方式使迭代器实现了非常强大的抽象。
Iterator特征具有一个名为IntoIterator的兄弟特征,它由想要转换为迭代器的类型实现,并提供了into_iter方法,该方法通过self获取实现类型从而使用该类型的元素。
让我们为某个自定义类型实现Iterator特征,如果该类型不是集合,那么请先确定要在数据类型中迭代的内容,然后创建一个保存迭代器任意状态的包装器结构体。通常,我们会发现迭代器是为某些包装器类型实现的,它通过所有权或者可变或不可变引用来引用集合类型中的元素。将类型转换为迭代器的方法也遵循常规的命名约定。
- iter()通过引用获取元素。
- iter_mut()用于获取元素的可变引用。
- into_iter()用于获取值的所有权,并在完全迭代后使用实际类型,原始集合将无法再访问。
实现Iterator特征的类型可以在for循环中使用,并且可以调用相关元素的next方法。考虑如下for循环代码:
for i in 0..20 {
// do stuff
}
上述包含语法糖的代码可以转换成如下形式:
let a = Range(..);
while let Some(i) = a.next() {
// do stuff
}
它将重复调用a.next()直到它和Some(i)变体相匹配。当它匹配的结果是None时,迭代将停止。