【Rust自学】13.5. 迭代器 Pt.1:迭代器的定义、iterator trait和next方法

13.5.0. 写在正文之前

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

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

  • 闭包
  • 迭代器(本文)
  • 使用闭包和迭代器改进I/O项目
  • 闭包和迭代器的性能

喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)

13.5.1. 什么是迭代器

提到迭代器,就得先讲迭代器模式。迭代器模式允许你依次对一系列项里的每一个元素执行某些任务。 而在这个过程中,迭代器负责:

  • 遍历每个项
  • 确定序列(的遍历)何时完成

Rust的迭代器是懒惰的(lazy):除非调用消费迭代器的方法,否则迭代器本身没有任何效果。这句话的意思大致是如果你在代码里写了迭代器但没有用到,那么迭代器就相当于什么都没干。

看个例子:

rust 复制代码
fn main() {
	let v1 = vec![1, 2, 3];
	let v1_iter = v1.iter();
}

v1是一个Vector,v1.iter()就是在给v1产生了一个迭代器,赋给了v1_iter,但是目前v1_iter没有被使用,所以迭代器可以被看作没有任何效果。

那我们使用迭代器来遍历:

rust 复制代码
fn main() {
	let v1 = vec![1, 2, 3];
	let v1_iter = v1.iter();
	for val in v1_iter {
		println!("Got: {}", val);
	}
}

这就相当于迭代器里的每个元素都被用在了一次循环里。

13.5.2. Iterator trait

所有的迭代器都实现了Iterator trait。这个trait定义在标准库之下,定义大致如下:

rust 复制代码
pub trait Iterator {
    type Item;

    fn next(&mut self) -> Option<Self::Item>;

    // methods with default implementations elided
}

这里面涉及两个新语法:type item和Self::Item,这两个语法定义了与这个trait关联的类型,这部分放在以后的文章讲。现在你需要知道的就是实现Iterator trait需要你定义一个Item类型,它用于next方法的返回类型(迭代器的返回类型)。

iterator这个trait仅要求实现一个方法------next。next方法每次调用迭代器它都会返回迭代器中的一项,也就是迭代器中的一个元素,而由于返回类型是Option,所以返回的结果会被包裹在Option下的Some变体里。如果迭代结束,就会返回Option下的None。

实际使用时可以直接在迭代器上调用next方法,看个例子:

rust 复制代码
#[cfg(test)]
mod tests {
    #[test]
    fn iterator_demonstration() {
        let v1 = vec![1, 2, 3];

        let mut v1_iter = v1.iter();

        assert_eq!(v1_iter.next(), Some(&1));
        assert_eq!(v1_iter.next(), Some(&2));
        assert_eq!(v1_iter.next(), Some(&3));
        assert_eq!(v1_iter.next(), None);
    }
}
  • v1是一个Vector,v1_iter是v1的迭代器,由于下面的操作会被视为修改迭代器内容所以得加mut关键字声明为可用。
  • assert_eq!(v1_iter.next(), Some(&1));这句话是第一次调用next,就会返回Vector里第一个元素,用Some包裹,也就是Some(&1),这里是&1是因为迭代器的返回值是被Option类型包裹的不可变引用。
  • assert_eq!(v1_iter.next(), Some(&2));是第二次调用next,就会返回Vector里第二个元素,用Some包裹,也就是Some(&2)
  • 以此类推...
  • 在迭代器上调用next方法会更改迭代器用于跟踪其在序列中位置的内部状态 。换句话说,每一次调用就是消耗了这个迭代器里一个元素。而13.5.1中例子的for循环不需要mut是因为for循环实际上取得了v1_iter的所有权。

13.5.3. 几种迭代方法

刚才使用的 iter方法生成的是一个不可变引用的迭代器 ,通过next方法所取得的值实际上是指向Vector中的元素的不可变引用。

into_iter方法创建的迭代器会获得所有权。也就是它在迭代元素时会把元素移动到新的作用域内,并取得所有权。

iter_mut方法在遍历函数时使用的是可变的引用。

相关推荐
杜 硕16 小时前
从零开始的C++生活——第四讲
开发语言·c++·生活
云和数据.ChenGuang17 小时前
Python 集合(set)常用函数详解与实战案例
开发语言·python·深度学习·langchain
隔窗听雨眠17 小时前
从PHP2Shell回望:PHP内核漏洞的二十年演进与AI时代的攻防转折
开发语言·人工智能·php
lisw0517 小时前
分岔论揭示演化突变密码
开发语言·算法·数学建模
hunteritself17 小时前
AI 挖出 PHP「致命漏洞」!欧洲政府连夜关站,日本首相紧急喊话
开发语言·人工智能·php
IT_陈寒17 小时前
SpringBoot性能优化完全指南
前端·人工智能·后端
努力实干17 小时前
Qt/C++ 模块化设计与工程组织
开发语言·c++·qt
随性而行36017 小时前
企业微信 Webhook 接收不到消息?网络连通性、URL 签名验签与 API 返回错误码排查指南
java·网络·人工智能·后端·微信·企业微信
阿里嘎多学长17 小时前
2026-10-23 GitHub 热点项目精选
开发语言·程序员·github·代码托管
相隔一个图书馆的距离17 小时前
单测(三)Spring Boot 3.5.6 && @MockitoSpyBean / AOP / 循环依赖:静默吞错与运行期 NPE
java·spring boot·后端