使用迭代器处理一系列项目
迭代器模式允许您对 转。迭代器负责迭代每个项目的逻辑,并且 确定序列何时完成。当您使用迭代器时,您不会 必须自己重新实现该逻辑。
在 Rust 中,迭代器是惰性的,这意味着它们在你调用
使用迭代器来用完它的方法。例如,中的
示例 13-10 通过调用
在 上定义的方法。此代码本身不执行任何作
有用。v1
iter
Vec<T>
迭代器存储在变量中。创建
iterator 中,我们可以以多种方式使用它。在第 3 章的示例 3-5 中,我们
使用循环迭代数组,以在其每个数组上执行一些代码
项目。在后台,这隐式创建并使用了一个迭代器
但直到现在,我们才掩盖了它究竟是如何工作的。v1_iter
for
在示例 13-11 的示例中,我们将迭代器的创建与
在循环中使用迭代器。当使用
中的迭代器 ,迭代器中的每个元素都用于一个
迭代,打印出每个值。for
for
v1_iter
在没有标准库提供的迭代器的语言中, 你可能会通过在 index 处启动一个变量来编写相同的功能 0,使用该变量索引向量以获取值,以及 在循环中递增变量值,直到达到 向量中的项目。
迭代器为您处理所有这些逻辑,从而减少重复的代码 可能会搞砸。迭代器为您提供了更大的灵活性来使用相同的 logic 具有许多不同类型的序列,而不仅仅是数据结构 index into 的 like 向量。让我们看看迭代器是如何做到这一点的。
Iterator
trait 和 next
Method
所有迭代器都实现了一个名为 trait 的 trait,该 trait 在
标准库。trait 的定义如下所示:Iterator
#![allow(unused)] fn main() { pub trait Iterator { type Item; fn next(&mut self) -> Option<Self::Item>; // methods with default implementations elided } }
请注意,此定义使用了一些新语法:和 ,
它们定义了与此 trait 关联的类型。我们将讨论
关联类型在第 19 章中深入介绍。现在,您需要知道的是
此代码表示实现 trait 还需要您定义
一个类型,并且此类型用于方法的返回类型。换句话说,type 将是从
迭 代。type Item
Self::Item
Iterator
Item
Item
next
Item
该 trait 只要求实现者定义一个方法: 该方法,该方法一次返回迭代器的一个项目,当迭代结束时,返回 。Iterator
next
Some
None
我们可以直接在迭代器上调用该方法;示例 13-12 演示了
对创建的迭代器的重复调用返回哪些值
从向量。next
next
请注意,我们需要使 mutable:在
iterator 更改 iterator 用于跟踪 where 的内部状态
它在序列中。换句话说,此代码会消耗或用完
迭 代。每次调用 to 都会吃掉迭代器中的一个项目。我们不需要
当我们使用循环时,使 mutable 可变,因为循环采用
的所有权,并使其在幕后可变。v1_iter
next
next
v1_iter
for
v1_iter
另请注意,我们从 call 中获得的值是不可变的
对向量中值的引用。该方法生成一个迭代器
over 不可变引用。如果我们想创建一个迭代器,它采用
ownership 并返回 owned 值,我们可以调用 而不是 。同样,如果我们想迭代可变引用,我们可以调用 而不是 .next
iter
v1
into_iter
iter
iter_mut
iter
使用 Iterator 的方法
该 trait 有许多不同的方法,其中 default
标准库提供的实现;您可以了解这些
方法,方法是在标准库 API 文档中查找 trait。其中一些方法在其定义中调用该方法,该
是您在实现 trait 时需要实现该方法的原因。Iterator
Iterator
next
next
Iterator
调用的方法称为使用适配器,因为调用它们
用完了迭代器。一个例子是方法,它获取
迭代器,并通过重复调用 来迭代项目,因此
使用 iterator。当它迭代时,它会将每个项目添加到正在运行的
total 并在迭代完成时返回 total。示例 13-13 有一个
test 说明了该方法的用法:next
sum
next
sum
我们不允许在调用 之后使用 ,因为需要
我们调用它的迭代器的所有权。v1_iter
sum
sum
生成其他迭代器的方法
Iterator adapters 是在 trait 上定义的方法,它们没有
使用 iterator。相反,它们通过更改
原始迭代器的某些方面。Iterator
示例 13-14 显示了一个调用 iterator 适配器方法的示例,
它需要一个 Closure 来在迭代 Item 时调用每个 Item。
该方法返回一个新的迭代器,用于生成修改后的项。这
this 中的 closure 创建一个新的迭代器,其中 vector 中的每个项目都将是
递增 1:map
map
但是,此代码会生成警告:
$ cargo run
Compiling iterators v0.1.0 (file:///projects/iterators)
warning: unused `Map` that must be used
--> src/main.rs:4:5
|
4 | v1.iter().map(|x| x + 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: iterators are lazy and do nothing unless consumed
= note: `#[warn(unused_must_use)]` on by default
help: use `let _ = ...` to ignore the resulting value
|
4 | let _ = v1.iter().map(|x| x + 1);
| +++++++
warning: `iterators` (bin "iterators") generated 1 warning
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.47s
Running `target/debug/iterators`
示例 13-14 中的代码什么都没做;我们指定的 从来没有被叫到。该警告提醒我们原因:iterator 适配器是惰性的,并且 我们需要在这里使用 iterator。
为了修复此警告并使用迭代器,我们将使用方法
我们在第 12 章中使用了它,在示例 12-1 中使用了它。此方法
使用 iterator 并将结果值收集到集合数据中
类型。collect
env::args
在示例 13-15 中,我们收集了迭代器的结果,该迭代器是
从调用 to 返回到 Vector 中。这个向量最终会得到
包含原始向量中递增 1 的每个项目。map
因为 take 一个闭包,所以我们可以指定我们想要执行的任何作
在每个项目上。这是一个很好的例子,说明闭包如何让你自定义一些
行为,同时重用 trait
提供。map
Iterator
您可以将多个调用链接到迭代器适配器,以在 一种可读的方式。但是因为所有的迭代器都是惰性的,所以你必须调用 使用 Adapter 方法从对 Iterator Adapter 的调用中获取结果。
使用捕获其环境的闭包
许多迭代器适配器将闭包作为参数,通常是闭包 我们将指定 as 参数 iterator adapters 将是捕获 他们的环境。
在此示例中,我们将使用采用闭包的方法。这
closure 从迭代器中获取一个项目并返回一个 .如果
返回 ,该值将包含在 生成的迭代中。如果 Closure 返回 ,则不会包含该值。filter
bool
true
filter
false
在示例 13-16 中,我们使用 with 一个闭包,从其环境中捕获变量来迭代 struct 的集合
实例。它将仅返回指定尺码的鞋子。filter
shoe_size
Shoe
该函数获取 shoes 和 shoe 的向量的所有权
size 作为参数。它返回一个向量,该向量仅包含指定
大小。shoes_in_size
在 的主体中,我们调用创建一个迭代器
,这需要向量的所有权。然后我们调用 以调整该
iterator 转换为新的迭代器,该迭代器仅包含闭包的
返回。shoes_in_size
into_iter
filter
true
闭包从环境中捕获参数,并且
将该值与每只鞋的尺码进行比较,仅保留该尺码的鞋子
指定。最后,调用 collect 由
adaptediterator 转换为函数返回的 vector。shoe_size
collect
测试表明,当我们调用 时,我们只得到 shoes
的大小与我们指定的值相同。shoes_in_size
本文档由官方文档翻译而来,如有差异请以官方英文文档(https://doc.rust-lang.org/)为准