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])
}
相关推荐
sensen_kiss16 小时前
CPT304 SoftwareEngineeringII 软件工程 2 Pt.9 软件测试 (Software Testing)(下)
学习·软件工程
wu_ye_m16 小时前
学习c语言第35天 函数声明和定义
c语言·开发语言·学习
Jurio.17 小时前
开源 Codex Sticky:在终端 Codex CLI 长对话中始终固定底部输入框
linux·rust·github·开源软件·codex·codex cli
清辞85317 小时前
Coze从入门到实战---第一、二章
大数据·人工智能·学习·语言模型
伊布拉西莫17 小时前
【流畅的Python】第20章:并发执行器 — 学习笔记
笔记·python·学习
jinglong.zha17 小时前
LScript-从零基础到商业变现的AI自动化学习平台
运维·学习·自动化
闪闪发亮的小星星18 小时前
STK_00 学习方案路线
学习
一楼的猫18 小时前
茄子写作助手——品牌搜索突破9万后的技术型品牌认知与官网入口指南
人工智能·学习·机器学习·chatgpt·ai写作
阿正的梦工坊19 小时前
【Rust】04-借用、引用与切片
java·数据库·rust
AOwhisky19 小时前
学习自测与解析:MySQL第五、六、七期核心知识点详解
运维·数据库·笔记·学习·mysql·云计算