rust语言学习笔记Trait(八)Iterator(迭代器)

在 Rust 中,迭代器是一个‌**惰性(Lazy)**‌的对象,它负责产生一系列值。与立即计算所有结果的集合不同,迭代器只有在被请求时(调用 .next())才会生成下一个值。

1、核心定义

rust 复制代码
pub trait Iterator {
    type Item; // 迭代产生的元素类型
    
    // 核心方法:返回下一个元素
    // Some(item): 还有下一个元素
    // None: 迭代结束
    fn next(&mut self) -> Option<Self::Item>;
    
    // ... 其他许多默认实现的方法如 map, filter, collect 等
}
  • 单一职责 ‌:next() 是唯一必须实现的方法。其他所有功能(如 map, filter)都是基于 next()构建的默认方法。
  • 状态性 ‌:迭代器内部维护状态(当前遍历到了哪里),因此调用 next()需要 &mut self a
  • 一次性消费 ‌:大多数迭代器只能遍历一次。一旦 next() 返回 None,迭代器通常就"耗尽"了。

2、创建迭代器的三种方式

Rust 集合(如 Vec, HashMap, 数组等)通常提供三种方法来创建迭代器,对应不同的所有权语义:

方法 签名示例 产出类型 (Item) 所有权行为 适用场景
‌**.iter()**‌ vec.iter() &T (不可变引用) 借用‌原始集合 只读遍历,保留集合所有权
‌**.iter_mut()**‌ vec.iter_mut() &mut T (可变引用) 可变借用‌原始集合 需要修改集合中的元素
‌**.into_iter()**‌ vec.into_iter() T (拥有所有权) 移动‌原始集合 消耗集合,获取元素所有权

3、迭代适配器

适配器是 Iterator trait 提供的默认方法,它们接收一个迭代器,经过转换后返回‌一个新的迭代器‌。

核心特性:惰性求值(Laziness)
调用适配器(如 .map(), .filter())‌
不会立即执行任何计算
‌。它们只是构建了处理逻辑的结构。只有当调用‌消费方法 ‌(如 .collect(), .sum(), .next(), .for_each())时,整个链条才会真正执行。

(1)转换类

  • map(f):对每个元素应用函数 f

    rust 复制代码
    let val = (1..6).map(|x| x * 3).collect::<Vec<_>>(); 
    // [3, 6, 9, 12, 15]
  • enumerate():将索引和元素配对,产出 (usize,Item)

    rust 复制代码
    let val = (1..6).enumerate().collect::<Vec<_>>();
    // [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]
  • zip(other):将两个迭代器压缩成一个,产出元组 (Item1,Item2)。长度以较短者为准。

    rust 复制代码
    let val = (1..6).zip((15..30)).collect::<Vec<_>>();
    // [(1, 15), (2, 16), (3, 17), (4, 18), (5, 19)]

(2)过滤类

  • filter(predicate):返回闭包条件为true 的元素

    rust 复制代码
    let val = (1..6).filter(|x| x % 2 == 0).collect::<Vec<_>>();
    // [2, 4]
  • take(n):前 n 个元素。

    rust 复制代码
    let val = (1..10).take(3).collect::<Vec<_>>();
    // [1, 2, 3]
  • skip(n):跳过前 n 个元素。

    rust 复制代码
    let val = (1..10).skip(3).collect::<Vec<_>>();
    // [4, 5, 6, 7, 8, 9]

(3)扁平化类

  • flat_map(f):闭包返回一个迭代器,然后将所有子迭代器"扁平"连接成一个流。常用于处理 Option 或嵌套集合。

    rust 复制代码
    // 处理嵌套集合
    let lists = vec![vec![1, 2], vec![3, 4]];
    let val: Vec<i32> = lists.into_iter().flat_map(|list| list.into_iter()).collect();
    // [1, 2, 3, 4]
    rust 复制代码
    // 处理 Option
    let strings = vec!["1", "hello", "3", "world", "5"];
    let numbers: Vec<i32> = strings.iter()
        .flat_map(|s| s.parse::<i32>().ok())
        .collect();
    // [1, 3, 5]
    • ‌**流程解析:**‌
      1. "1" -> parse -> Ok(1) -> .ok() -> Some(1) -> flat_map 产出 1
      2. "hello" -> parse -> Err(...) -> .ok() -> None -> flat_map跳过
      3. "3" -> parse -> Ok(3) -> .ok() -> Some(3) -> flat_map 产出 3
        ...以此类推。
    • 如果你的闭包明确返回 Option,请优先使用 ‌**filter_map**‌,用法相同。

(4)消费方法

  • collect::<B>():迭代器转为集合。

  • sum() :求和。

    rust 复制代码
    let val: i32 = (1..10).sum();
    // 45
  • product():乘积。

    rust 复制代码
    let val: i32 = (1..10).product();
    // 362880
  • fold(init, f):向左折叠,累个计算

    rust 复制代码
    let val = (1..10).fold(0, |a, x| a + x);  // 求和 1+2+..9
    let val = (1..10).fold(0, |a, x| a * x);  // 乘积 1*2*..9
    let val = (1..10).fold(0, |a, x| a - x);  // 连减 1-2-..9
  • find(predicate):返回第一个满足条件的元素引用(Option<&Item>),找到后立即停止。

    rust 复制代码
    let val = (1..10).find(|&x| x % 3 == 0);
    // Some(3)
  • any():是否有任何元素满足条件,支持短路求值。

    rust 复制代码
    let val = (1..10).any(|x| x % 3 == 0);
    // true
  • all():是否有所有元素满足条件,支持短路求值。

    rust 复制代码
    let val = (1..10).all(|x| x % 3 == 0);
    // false

4、自定义迭代器实现 Iterator

rust 复制代码
struct MyIter {                   // 自定义迭代器
    val: u32,                     // 初始值的前一个值
    max: u32,                     // 最大值
}
impl MyIter {
    fn new(max: u32) -> MyIter {  // 根据最大值初始化迭代器
        MyIter { val: 0, max }
    }
}
impl Iterator for MyIter {
    type Item = u32;
    fn next(&mut self) -> Option<Self::Item> {
        if self.val < self.max {
            self.val += 1;        // 下一个值 = 上一个值加一
            Some(self.val)        // 返回当前值
        } else {
            None                  // 为None时,结束迭代
        }
    }
}

fn main() {
    let val = MyIter::new(5).collect::<Vec<_>>();
    println!("{:?}", val);      // [1, 2, 3, 4, 5]
}

5、自定义类型实现 IntoIteratorIterator

  • **IntoIterator (工厂接口)**‌:定义了一个类型如何被"加工"成迭代器。生成迭代器
  • Iterator (产品行为)‌:定义了迭代器本身的行为(即 next() 方法)。‌产生值
rust 复制代码
// 自定义类型
#[derive(Debug)]
struct MyList(Vec<u32>);

impl IntoIterator for MyList {                   // 实现 IntoIterator,转为迭代器
    type Item = u32;
    type IntoIter = MyIter;                      // 迭代器类型为自定义迭代器
    fn into_iter(self) -> Self::IntoIter {
        MyIter { 
            data: self.0,                        // 将Vec所有权移动到迭代器中      
            index: 0,                            // 初始化索引
        }
    }
}

// 自定义迭代器
struct MyIter {
    data: Vec<u32>,                 // 迭代器的值
    index: usize,                   // 索引位置
}

impl Iterator for MyIter {                          // 实现迭代器
    type Item = u32;
    fn next(&mut self) -> Option<Self::Item> {
        if self.index < self.data.len() {
            let item = self.data[self.index];      // 当前索引的值
            self.index += 1;                       // 下一个索引
            Some(item)                             // 返回当前值
        } else {
            None                                   // None时,结束迭代
        }
    }
}

fn main() {
    let list = MyList(vec![1, 2, 3]);
    println!("{:?}", list);                    // MyList([1, 2, 3])
}
相关推荐
华为云开发者联盟5 小时前
告别繁琐操作,华为云码道 + Docker重塑远程开发体验
人工智能·学习·docker·华为云·软件开发·华为云码道
Bechamz5 小时前
大数据开发学习Day38
大数据·学习
-To be number.wan5 小时前
计算机组成原理 | 原码一位乘法运算方法
学习·计算机组成原理
前端若水6 小时前
从零开始学习AI Agent的实战路线图
人工智能·学习
ZhiqianXia6 小时前
流畅的Python笔记
笔记·python
魔法阵维护师6 小时前
从零开发游戏需要学习的c#模块,第十一章(rpg小游戏入门,上篇,地图与移动)
学习·游戏·c#
qq_525513756 小时前
# 第七章 指令微调学习(四) 7.6基于指令数据对大语言模型进行微调
深度学习·学习·语言模型
玄米乌龙茶1236 小时前
LLM成长笔记(四):大语言模型(LLM)基础认知
人工智能·笔记·语言模型
问心无愧05136 小时前
ctf show web入门157
笔记