Rust进阶[part8]_迭代器

Rust进阶[part8]_迭代器&关联类型

概述

迭代器(Iterator)是 Rust 中处理序列元素的强大工具,它提供了一种统一的方式来遍历集合(如向量、数组、哈希表等)中的元素。迭代器的核心特性是惰性执行:除非主动调用消耗迭代器的方法,否则迭代器不会实际执行任何操作。这种特性使得迭代器可以高效地组合使用,而不会带来额外的性能开销。

在 Rust 中,迭代器由 Iterator trait 定义,所有实现了该 trait 的类型都可以被称为迭代器。迭代器不仅可以用于遍历现有集合,还可以用于生成序列(如斐波那契数列)、处理数据流等场景。

迭代器的实现

迭代器本质是实现了 Iterator trait 的类型。该 trait 的核心定义如下:

trait Iterator {
    type Item;  // 关联类型:迭代器产生的元素类型
    fn next(&mut self) -> Option<Self::Item>;  // 核心方法:返回下一个元素(None表示结束)
}

next 方法是迭代器的核心:

  • 每次调用返回 Option<Self::Item>,其中 Some(value) 表示下一个元素,None 表示迭代结束
  • 调用 next 会修改迭代器的内部状态(推进到下一个元素),因此需要 &mut self

关联类型

上面 trait 中用到的 type Item; 是关联类型(Associated Type),它是在 trait 内部定义的类型占位符,用于表示 trait 中涉及的某个类型。实现该 trait 时,需要指定 Item 的具体类型。

和泛型的区别

关联类型与泛型都可以实现"类型抽象",但适用场景不同:

  • 关联类型:在 trait 中只声明一个类型占位符,实现 trait 时必须为该类型指定唯一具体类型(一个实现对应一个具体类型)。适合 trait 中某个类型逻辑上"固定"的场景(如迭代器的元素类型)。

    // 迭代器只能产生一种类型的元素,用关联类型更合适
    trait Iterator {
        type Item;
        fn next(&mut self) -> Option<Self::Item>;
    }
  • 泛型:在 trait 定义时声明类型参数,实现 trait 时可以为不同类型参数提供多个实现。适合需要为多种类型提供通用逻辑的场景。

    // 泛型可以为不同T实现不同逻辑
    trait Container<T> {
        fn get(&self, index: usize) -> Option<&T>;
    }

简单迭代器

迭代器的基本使用示例:

fn iter_study() {
    let v1 = vec![1, 2, 3];
    // 1. for循环遍历(最常用)
    let v1_iter = v1.iter();  // 获取迭代器(不可变引用)
    for var in v1_iter {
        println!("{}", var);  // 输出:1 2 3
    }

    // 2. 手动调用next方法
    let mut v1_iter2 = v1.iter();  // 需要mut,因为next会修改迭代器状态
    while let Some(var) = v1_iter2.next() {
        println!("{}", var);  // 输出:1 2 3
    }
}

for 循环不需要 mut 而 while 循环需要的原因
for 循环在内部会自动处理迭代器的可变性——它会将迭代器标记为 mutable,并在循环过程中隐式调用 next 方法。而手动调用 next 时,需要显式声明 mut,因为 next 方法接收 &mut self,要求迭代器是可变的。

几个迭代的方法

集合类型(如 Vec)通常提供以下方法来获取不同类型的迭代器:

iter 方法

返回不可变引用迭代器Iterator<Item = &T>),迭代过程中借用集合元素(不获取所有权),集合本身可以在迭代后继续使用。

let v = vec![1, 2, 3];
let iter = v.iter();  // 迭代元素类型:&i32

into_iter 方法

返回所有权迭代器Iterator<Item = T>),迭代过程中会获取集合元素的所有权,迭代结束后集合本身无法再使用(已被消耗)。

let v = vec![1, 2, 3];
let iter = v.into_iter();  // 迭代元素类型:i32(v此后不可用)

iter_mut 方法

返回可变引用迭代器Iterator<Item = &mut T>),迭代过程中可以修改集合元素的值。

let mut v = vec![1, 2, 3];
let iter = v.iter_mut();  // 迭代元素类型:&mut i32
for num in iter {
    *num *= 2;  // 修改元素值
}
println!("{:?}", v);  // 输出:[2, 4, 6]

消耗迭代器的方法

消耗型方法(Consuming Adaptors)会遍历迭代器并消耗它(调用后迭代器无法再使用),通常会产生一个最终结果。

next

最基础的消耗型方法,每次调用返回下一个元素,直到返回 None

sum

计算迭代器中所有元素的总和,支持所有实现了 Sum trait 的类型(如数值类型)。

let v = vec![1, 2, 3, 4];
let total: i32 = v.iter().sum();  // sum会消耗迭代器
println!("{}", total);  // 输出:10

collect

将迭代器产生的元素收集到一个集合中(如 VecHashMap 等),需要显式指定目标集合类型。

let v = vec![1, 2, 3];
let doubled: Vec<i32> = v.iter().map(|x| x * 2).collect();  // 收集到Vec
println!("{:?}", doubled);  // 输出:[2, 4, 6]

产生其他迭代器的方法

迭代器适配器(Iterator Adaptors)会对迭代器进行转换,产生一个新的迭代器(不立即执行,仍保持惰性)。

map

接收一个闭包作为参数,将迭代器中的每个元素转换为另一种类型,返回一个新的迭代器。

let v = vec![1, 2, 3];
let mapped = v.iter().map(|x| x * 10);  // 类型:Map<Iter<i32>, ...>(未执行)
// 用collect触发执行
let result: Vec<i32> = mapped.collect();
println!("{:?}", result);  // 输出:[10, 20, 30]

filter

接收一个闭包作为 predicate(断言),该闭包返回 bool,新迭代器只包含满足断言的元素。

let v = vec![1, 2, 3, 4, 5];
let even_numbers: Vec<&i32> = v.iter().filter(|x| **x % 2 == 0).collect();
println!("{:?}", even_numbers);  // 输出:[2, 4]

练习:实现斐波那契数列迭代器

题目描述

实现一个自定义迭代器,用于生成斐波那契数列。该迭代器应支持无限生成斐波那契数,直到用户停止迭代。

任务要求

  1. 实现结构体 Fibonacci,并为它实现 Iterator trait。
  2. next 方法中生成下一个斐波那契数。
  3. 编写测试函数,输出前10个斐波那契数。

实现代码


use std::iter::Iterator;

// 定义斐波那契迭代器结构体,存储当前和下一个斐波那契数
struct Fibonacci {
    current: u64,
    next: u64,
}

// 为Fibonacci实现Iterator trait
impl Iterator for Fibonacci {
    type Item = u64;  // 迭代器产生u64类型的斐波那契数

    fn next(&mut self) -> Option<Self::Item> {
        let current_val = self.current;  // 保存当前值作为返回结果
        // 更新下一组值(斐波那契规则:下一个数 = 当前数 + 前一个数)
        let new_next = self.current + self.next;
        self.current = self.next;
        self.next = new_next;
        Some(current_val)  // 始终返回Some(无限迭代)
    }
}

// 提供一个构造函数,初始化斐波那契迭代器(从0, 1开始)
impl Fibonacci {
    fn new() -> Self {
        Fibonacci { current: 0, next: 1 }
    }
}

// 测试函数:输出前10个斐波那契数
fn test_fibonacci() {
    let fib_iter = Fibonacci::new();
    // take(10)限制只取前10个元素(迭代器适配器)
    for (i, num) in fib_iter.t  ake(10).enumerate() {
        println!("第{}个斐波那契数:{}", i + 1, num);
    }
}

// 运行测试
fn main() {
    test_fibonacci();
}

输出结果

第1个斐波那契数:0
第2个斐波那契数:1
第3个斐波那契数:1
第4个斐波那契数:2
第5个斐波那契数:3
第6个斐波那契数:5
第7个斐波那契数:8
第8个斐波那契数:13
第9个斐波那契数:21
第10个斐波那契数:34

说明

  • 结构体 Fibonaccicurrentnext 存储当前和下一个斐波那契数,初始化为 01(符合斐波那契数列的数学定义)。
  • next 方法通过更新 currentnext 的值生成下一个数,始终返回 Some(实现无限迭代)。
  • 使用 take(10) 适配器限制只获取前10个元素,避免无限循环。