1、大多数集合类型提供了 iter 和 iter_mut 方法,返回该类型的迭代器,产生每个迭代项的共享或可修改引用。切片类型 &[T] 和 &str 也有iter 和 iter_mut 方法。
let v = vec![4, 20, 12]; let mut iterator = v.iter();
assert_eq!(iterator.next(), Some(&4));
assert_eq!(iterator.next(), Some(&20));
assert_eq!(iterator.next(), Some(&12));
assert_eq!(iterator.next(), None);
2、如果类型实现了 IntoIterator,则可以调用它的 into_iter 方法,跟for 循环一样。实际上大多数集合提供了不止一个 IntoIterator 的实现,分别用于共享引用、可修改引用和转移。
并不是所有类型都会提供全部 3 种实现。例如,HashSet、BTreeSet 和BinaryHeap 就没有对可修改引用实现 IntoIterator,因为修改它们的元素可能违背类型的不变性,比如被修改的值变成不同的散列值或者相对周边元素做了不同排序,导致修改后把元素放到错误的位置上。其他类型确实有支持可修改引用的,但只是部分支持。例如,HashMap 和 BTreeMap会产生它们值的可修改引用,但只产生它们键的共享引用,原因与前面所讲类似
切片实现了 3 种 IntoIterator 变体中的两个,因为它本身没有元素的所有权,所以就没有“按值”这种情况。而 &[T] 和 &mut [T] 的into_iter 返回的迭代器,可以产生对它们元素的共享引用和可修改引用。如果把底层切片类型 [T] 想象为某种类型的集合,就能从整体上理解这种实现了
3、其他的如下,还有很多,大家自己自行去找找看。
std::ops::Range
Option
Result
String, &str s.bytes()、s.chars()、s.lines()
Rust中的迭代器都是惰性的,它们不会自动发生遍历行为,必须调用next方法去消费其中的数据。所以在Iterator trait提供的默认方法中调用next的方法也被称为消耗适配器,因为它们同样消耗了迭代器本身。这也是我们需要在实现Iterator trait时手动定义next方法的原因。
面介绍常用的消费器collect,其他消费器可以在std::iter::Iterator中找到。collect可以将迭代器转换成指定的容器类型,即将迭代器中的元素收集到指定的容器中。
fn main() {
let v1 = [1, 2, 3, 4, 5];
let v2: Vec = v1.iter().map(|x| x + 1).collect();
println!("{:?}", v2);
}
// [2, 3, 4, 5, 6]
通过iter方法将数组转换为迭代器,再使用map方法对原迭代器中的每个元素调用闭包执行加1操作并生成一个新迭代器,最后调用collect方法将新迭代器中的元素收集到动态数组中。
Iterator 提供大量可供选择的适配器方法,它会将当前迭代器转换成另一种类型的迭代器,并支持链式调用多个迭代器适配器。不过,由于所有的迭代器都是惰性的,必须使用一个消费器来获取迭代器适配器的调用结果。下面介绍常用的迭代器适配器map、take、filter等,其他迭代器适配器可以在std::iter中找到。
fn main() {
let v = vec![1,2,3,4,5,6,7,8,9];
let mut iter = v.iter()
.take(5)
.filter(|&x| x % 2 == 0) .map(|&x| x * x) .enumerate();
while let Some((i, v)) = iter.next() { println!("{} {}", i, v);
}
通过take获取前5个数字,使用filter找到偶数,然后通过map实现平方,最后返回下标和数字本身。
我们试一下如何实现一个迭代器。 假设我们的目标是, 这个迭代器会生成一个从1到10的序列。 我们创建一个struct,实现Iterator trait。 由于每次调用next方法的时候, 它都返回下一个值, 所以我们添加一个成员, 记录当前的状态。 代码如下
use std::iter::Iterator;
struct Seq {
current : i32
}
impl Seq {
fn new() -> Self {
Seq { current: 0 }
}
}
impl Iterator for Seq {
type Item = i32;
fn next(&mut self) -> Option {
if self.current < 10 {
self.current += 1;
return Some(self.current);
} else {
return None;
}
}
}
fn main() {
let mut seq = Seq::new();
while let Some(i) = seq.next() {
println!("{}", i);
}
}
当然,for 循环要使用 IntoIterator::into_iter 将其操作数转换为一个迭代器。但标准库为每个实现 Iterator 的类型都提供了对IntoIterator 的通用实现,因此 Seq 已经可以使用了
自定义类型也可以实现 IntoIterator 和 Iterator 特型,从而可以让本章介绍的所有适配器和消费者都派上用场,当然还包括使用标准迭代器接口的第三方库。