概念

迭代器用来遍历序列中的每一项,它也决定了什么时候结束迭代。

迭代器是惰性的,因此迭代器的使用分为两步:创建和消费
示例:

  1. let v1 = vec![1, 2, 3];
  2. // 获取迭代器
  3. let v1_iter = v1.iter();
  4. // 使用for循环消费迭代器
  5. for val in v1_iter {
  6. println!("Got: {}", val);
  7. }

迭代器实现了Iterator这一**trait**trait的定义如下:

  1. pub trait Iterator {
  2. // 定义一个关联类型
  3. type Item;
  4. // 定义next的实现
  5. fn next(&mut self) -> Option<Self::Item>;
  6. // 此处省略了方法的默认实现
  7. }

实现了Iterator traitstruct就可以成为一个迭代器

获取迭代器

获取迭代器的方式

  1. v.iter()
  2. v.iter_mut()
  3. v.into_iter()

image.png

内部元素的类型

Vector<**T**>来说:

  1. 获取引用**&T**
    1. v.iter()
    2. (&v).into_iter()
  2. 获取可变引用**&mut T**
    1. v.iter_mut()
    2. (&mut v).into_iter()
  3. 获取所有权**T**
    1. v.into_iter()

下面显式调用三种获取迭代器的方法, 可以观察获取到的元素类型
image.png

for 循环自动调用 into_iter()

在为v使用for循环时,会为v自动调用into_iter()方法获取迭代器,因此可以在v前加&& mut或直接v,以此获取变量的引用、可变引用、所有权
示例:

  1. let mut vec = vec!(1,2,3);
  2. // 值被移动
  3. // 自动调用 v.into_iter()
  4. for x in v {
  5. println!("x = {}", x);
  6. }
  7. -----------------------------
  8. // 自动调用 (&v).into_iter()
  9. for x in &v {
  10. println!("x = {}", x);
  11. }
  12. // 等价于
  13. for x in v.iter() {
  14. println!("x = {}", x);
  15. }
  16. ------------------------------
  17. // 自动调用 (&mut v).into_iter()
  18. for x in &mut v {
  19. println!("x = {}", x);
  20. }
  21. // 等价于
  22. for x in v.iter_mut() {
  23. println!("x = {}", x);
  24. }

为自定义类型实现 into_iter()

  1. struct CountdownIterator(i32);
  2. impl Iterator for CountdownIterator {
  3. type Item = i32;
  4. fn next(&mut self) -> Option<Self::Item> {
  5. self.0 -= 1;
  6. if self.0 < 0 {
  7. None
  8. } else {
  9. Some(self.0)
  10. }
  11. }
  12. }
  13. struct Countdown(i32);
  14. impl IntoIterator for Countdown {
  15. type Item = i32;
  16. type IntoIter = CountdownIterator;
  17. fn into_iter(self) -> Self::IntoIter {
  18. CountdownIterator(self.0)
  19. }
  20. }
  21. impl<'a> IntoIterator for &'a Countdown {
  22. type Item = i32;
  23. type IntoIter = CountdownIterator;
  24. fn into_iter(self) -> Self::IntoIter {
  25. CountdownIterator(self.0)
  26. }
  27. }
  28. impl<'a> IntoIterator for &'a mut Countdown {
  29. type Item = i32;
  30. type IntoIter = CountdownIterator;
  31. fn into_iter(self) -> Self::IntoIter {
  32. CountdownIterator(self.0)
  33. }
  34. }
  35. fn main() {
  36. let c = Countdown(10);
  37. for i in &c {
  38. for j in &c {
  39. println!("({0}, {1})", i, j)
  40. }
  41. }
  42. }

Vector的迭代器实现

iter()、iter_mut()方法

是结构体的自有方法
定义:

  1. pub fn iter(&self) -> Iter<'_, T> {
  2. Iter::new(self)
  3. }
  4. pub fn iter_mut(&mut self) -> IterMut<'_, T> {
  5. IterMut::new(self)
  6. }

**Iter**来自Struct std::slice::Iter
**IterMut**来自Struct std::slice::IterMut

Vector使用了**slice**中定义的迭代器

into_iter()方法

实现了**IntoIterato trait**中的**into_iter()**方法
定义:

  1. pub trait IntoIterator {
  2. type Item;
  3. type IntoIter: Iterator;
  4. fn into_iter(self) -> Self::IntoIter;
  5. }

有三个实现:

  1. // 获取借用
  2. impl<'a, T, A> IntoIterator for &'a mut Vec<T, A> where
  3. A: Allocator,
  4. // 获取可变借用
  5. impl<'a, T, A> IntoIterator for &'a Vec<T, A> where
  6. A: Allocator,
  7. // 获取所有权
  8. impl<T, A> IntoIterator for Vec<T, A>

消费适配器(consuming adaptors)

Iterator trait中存在一些有默认实现其他方法,它们的实现中调用了next()方法(也就是对迭代器进行消费),这些方法被称为消费适配器(consuming adaptors)

使用sum消费适配器的示例:

  1. fn iterator_sum() {
  2. let v1 = vec![1, 2, 3];
  3. let v1_iter = v1.into_iter();
  4. // 调用sum会获取v1_iter的所有权,因此后面不可再使用v1_iter
  5. let sum: i32 = v1_iter.sum();
  6. assert_eq!(sum, 6);
  7. }

迭代器适配器(iterator adaptors)

Iterator trait中还有一类迭代器适配器(iterator adaptors)方法,这些方法将前一个迭代器转换为另一个迭代器迭代器适配器可以链式调用。

示例:

  1. fn iterator_adaptors() {
  2. let v1 = vec![1, 2, 3, 4];
  3. // 调用map对迭代器进行转换
  4. // collect方法属于env::args,用于消费迭代器返回一个新vector
  5. let v1_new_vec: Vec<i32> = v1.iter().map(|x| x + 2).collect();
  6. assert_eq!(v1_new_vec, vec![3, 4, 5, 6]);
  7. }

综合使用:自定义迭代器实现

描述:

  1. 创建迭代器的结构体定义
  2. 为结构体实现**new**函数,返回结构体实例
  3. 为结构体实现**Iterator trait**重写**next**方法
  4. 测试
    1. 调用**zip**方法。返回一个由2-元组组成的新迭代器,元组中的两个元素分别来自两个迭代器,下面示例的zip方法中:
      1. 第一个迭代器中为1,2,3,4,5
      2. 第二个迭代器中为2,3,4,5
      3. 结果为(1,2),(2,3),(3,4),(4,5),第五对值:(5,None)实际上从未产生过
    2. 调用map方法后,结果为2,6,12,20
    3. 调用filter方法后,结果为6,12
    4. 计算sum后,结果为18

示例:

  1. // 迭代器定义
  2. struct CounterIterator {
  3. count: u32,
  4. }
  5. impl CounterIterator {
  6. fn new() -> CounterIterator {
  7. CounterIterator { count: 0 }
  8. }
  9. }
  10. // 实现Iterator trait并重写next方法的实现
  11. impl Iterator for CounterIterator {
  12. type Item = u32;
  13. fn next(&mut self) -> Option<Self::Item> {
  14. self.count += 1;
  15. if self.count < 6 {
  16. Some(self.count)
  17. } else {
  18. None
  19. }
  20. }
  21. }
  22. #[test]
  23. fn coustom_iterator_trait() {
  24. let iter = CounterIterator::new();
  25. // 连续调用迭代器消费器
  26. let sum: u32 = iter
  27. .zip(CounterIterator::new().skip(1))
  28. .map(|(a, b)| a * b)
  29. .filter(|x| x % 3 == 0)
  30. .sum();
  31. assert_eq!(sum, 18);
  32. }

迭代器的可变引用

消耗迭代器所有权

如果在迭代器上调用参数为**self**消费器, 例如下面的take方法, 这个迭代器会被消耗, 之后无法使用
fn [take](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.take)(**self**, n: [usize](https://doc.rust-lang.org/std/primitive.usize.html)) -> [Take](https://doc.rust-lang.org/std/iter/struct.Take.html)<Self> take方法拿走原迭代器**n**元素, 返回新迭代器

这里的返回值Take是迭代器类型, 也就说调用take方法返回了一个新的迭代器:
image.png

获取迭代器的可变引用

所以可以先拿到迭代器的可变引用, 这样的话即使调用参数为**self**消费器, 效果也相当于**&mut self**
这个方法是fn [by_ref](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.by_ref)(&mut self) -> [&mut](https://doc.rust-lang.org/std/primitive.reference.html)Self by_ref方法借用一个迭代器, 而不是消费它

可变引用也实现了迭代器

原因是有个一揽子泛型实现: 它为迭代器的可变引用实现了Iterator trait:
image.png

可以看到里面有两次解引用操作, 以next为例, 它要获取参数的可变引用&mut self, 而此时的self类型是已经是可变引用类型&mut I, 所以next拿到的类型是**&mut &mut self**, 所以需要两次解引用操作, 经过take方法也是一样, 因为take直接返回的类型就是参数类型