【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方法在遍历函数时使用的是可变的引用。

相关推荐
子兮曰4 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰4 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
小羊没烦恼!4 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
爱勇宝4 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
胡写代码4 天前
别再前后端各写一套表单校验了
java·后端
伞伞悦读4 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
大勇前进4 天前
原生 PHP 还是 Laravel?小项目到底要不要上框架
后端
yuzhi_liu4 天前
我用 LangGraph4j 实现 Multi-Agent Supervisor
后端
alsmile4 天前
Node-RED 之外,国产规则引擎的新方案:基于标准语法,Go 先行实现
后端·开源·go
大白804 天前
PHP 内存溢出排查思路:看懂报错日志,精准定位问题
后端