Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

13.8 迭代器 Pt.4:创建自定义迭代器

13.8.0. 写在正文之前

Rust语言在设计过程中受到了很多语言的启发,而函数式编程对Rust产生了非常显著的影响。函数式编程通常包括通过将函数作为值传递给参数、从其他函数返回它们、将它们分配给变量以供以后执行等等。

在本章中,我们会讨论 Rust 的一些特性,这些特性与许多语言中通常称为函数式的特性相似:

13.8.1. 使用Iterator trait创建自定义迭代器

最主要的步骤就只有一步:提供next方法的实现。

看个例子:

做一个迭代器,从1遍历到5

#![allow(unused)]
fn main() {
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 < 5 {
            self.count += 1;
            Some(self.count)
        } else {
            None
        }
    }
}
}
  • 先创建一个结构体叫Counter,它有count字段,用来存储迭代过程中所需要的数值,也就是迭代过程中的状态。这里count字段不使用pub而是设为私有是为了让Counter结构体独立管理它的值。

  • 然后在这个结构体上写了一个关联函数new用于创建新的实例,确保新实例从0开始。

  • 下面就需要为Counter这个结构体实现Iterator这个trait。Iterator trait有一个关联类型type Item还有一个next方法。首先把关联类型指定为u32,也就是写type Item = u32;。这个语法在 19.2. 高级trait 会细讲,现在知道这个迭代器会返回u32类型即可。

  • next函数的返回类型是Option<Self::Item>,由于上文写了关联类型指定为u32,所以可以理解为Option<u32>。当count字段小于5的时候就继续加1,如果大于等于5就返回None。这样就能保证从1到5的遍历。

现在我们来实现复杂一些的需求:

同样使用Counter结构体:一个从1到5,另一个从2到5。把两个迭代器的每对元素相乘,只保留新迭代器中能被3整除的元素,然后返回这些元素的和

#![allow(unused)]
fn main() {
fn using_other_iterator_traits_methods() {
    let sum: u32 = Counter::new()
        .zip(Counter::new().skip(1))
        .map(|(a, b)| a * b)
        .filter(|x| x % 3 == 0)
        .sum();
}
}
  • 这里我分行写是因为链式调用写在一行太长了,如果链式调用的代码没多长就没必要分行写
  • zip方法是把两个迭代器的每对元素和到一起形成新迭代器,这个新迭代器的元素就是元组,每个元组有两个值,分别来自两个迭代器。
  • Counter::new()就是建立一个从1到5的Counter结构体,Counter::new().skip(1)就是建立跳过1的Counter结构体,也就是从2到5。把这两个结构体实例使用zip和到一起就会形成如下表格的存储元组(Tuple)的迭代器:
Counter::new()Counter::new().skip(1)
Tuple 012
Tuple 123
Tuple 234
Tuple 345
PS:Counter::new()不会遍历到5是因为Counter::new().skip(1)在那时的值是None,程序就不会再生成值
  • map接收一个闭包,闭包作用于迭代器的每个元素。它把当前迭代器的每个元素给转换为另外一个元素,然后这些另外的元素就组成了一个新的迭代器。在这个例子中就是把迭代器存储的元组里的两个值相乘得到新的迭代器。
  • filter通过闭包把能整除3的值留下形成新的迭代器
  • sum消耗迭代器的所有元素,把其中的所有值相加求和

最后的结果应该是18