跳到主要内容

Rust迭代器

提示
  1. Rust迭代器基础:在Rust中,迭代器用于创建值的序列,可通过循环遍历,如数组。使用iter()方法将数据结构转换为迭代器,允许遍历其元素。
  2. 迭代器的方法next()方法用于单个值遍历,返回Some值或到达末尾时返回None。不同的迭代器创建方法(iter(), into_iter(), iter_mut())提供不同的数据视图与修改能力。
  3. 迭代器适配器与范围:迭代器适配器(如map())可转换迭代器行为,需与collect()方法结合以产生结果。Rust支持使用范围表示法创建迭代器,如1..6,用于for循环。

在 Rust 中,迭代器负责创建一系列值,并允许我们遍历序列中的每个项。它主要用于循环,我们只能在 Rust 中对迭代器进行循环遍历。

让我们看一个简单的例子,了解如何遍历数组。

let numbers = [2, 1, 17, 99, 34, 56];

现在,让我们通过调用 iter() 方法将数组变为可迭代数组。如果数据结构有 iter() 方法,就称之为可迭代的。

let numbers_iterator = numbers.iter();

最后,我们可以遍历这些值并打印它们。

for number in numbers_iterator {
println!("{}", number);
}

注意: 像数组、向量、HashMap 和 HashSet 这样的集合默认不是可迭代的。我们可以使用 iter() 方法来告诉 Rust 它可以用来遍历这些值。

示例:Rust 中的迭代器

fn main() {
let numbers = [2, 1, 17, 99, 34, 56];

// 迭代器
let numbers_iterator = numbers.iter();

for number in numbers_iterator {
println!("{}", number);
}
}

输出

2
1
17
99
34
56

在这里,使用 numbers_iterator 中的迭代器调用 for..in 循环,迭代器中的每个值在一次迭代中被使用,然后打印到屏幕上。

Rust 迭代器的 next() 方法

迭代器的另一个重要方法是 next() 方法。next() 方法可以用于遍历迭代器中的值。

Rust 中的每个迭代器都会有 next() 方法。next() 方法用于从迭代器中获取单个值。

让我们看一个例子。

fn main() {
let colors = vec!["Red", "Yellow", "Green"];

// 迭代器
let mut colors_iterator = colors.iter();
println!("colors 迭代器 = {:?}", colors_iterator);

// 使用 next() 方法逐个获取迭代器中的值
println!("{:?}", colors_iterator.next());
println!("{:?}", colors_iterator.next());
println!("{:?}", colors_iterator.next());
println!("{:?}", colors_iterator.next());
}

输出

colors 迭代器 = Iter(["Red", "Yellow", "Green"])
Some("Red")
Some("Yellow")
Some("Green")
None

在这里,我们使用 next() 方法从 colors_iterator 中获取值。next() 方法要么返回 Some 值,要么返回 None

请注意,我们需要将 colors_iterator 声明为可变变量,因为调用 next() 会改变迭代器的内部状态。每次调用 next() 都会消耗迭代器中的一个项。

当迭代器到达序列末尾时,next() 方法将返回 None

在 Rust 中创建迭代器的方法

我们可以通过将集合转换为迭代器来创建迭代器。有三种方法可以创建迭代器。

  1. 使用 iter() 方法
  2. 使用 into_iter() 方法
  3. 使用 iter_mut() 方法

所有这些方法提供了对迭代器中数据的不同视图。

1. 使用 iter() 方法

对集合使用 iter() 方法将在每次迭代中借用(引用)集合的每个元素。因此,在我们遍历完它之后,集合仍然可用。

例如,

fn main() {
let colors = vec!["Red", "Yellow", "Green"];

// 使用 iter() 遍历集合
for color in colors.iter() {
// 对迭代器中的项进行引用
println!("{}", color);
}

// 这里集合未被更改,仍然可用
println!("colors = {:?}", colors);
}

输出

Red
Yellow
Green
colors = ["Red", "Yellow", "Green"]

注意,在使用 iter() 方法之后,colors 变量仍然可用。

2. 使用 into_iter() 方法

对集合使用 into_iter() 方法将在每次迭代中遍历集合的同一元素。因此,由于值在循环中移动,集合将不再可用于重复使用。

例如,

fn main() {
let colors = vec!["Red", "Yellow", "Green"];

// 使用 into_iter() 遍历集合
for color in colors.into_iter() {
// 集合中的项移动到这个作用域中
println!("{}", color);
}
// for 循环的作用域结束

// 错误
// 这里的集合不可用,因为 for 循环的作用域在上面结束
println!("colors = {:?}", colors);
}

输出

error[E0382]: borrow of moved value: `colors`
--> src/main.rs:11:31
|
2 | let colors = vec!["Red", "Yellow", "Green"];
| ------ move occurs because `colors` has type `Vec<&str>`, which does not implement the `Copy` trait
...
5 | for color in colors.into_iter() {
| ----------- `colors` moved due to this method call
...
11 | println!("colors = {:?}", colors);
| ^^^^^^ value borrowed here after move
|

注意,在使用 into_iter() 方法之后,colors 变量不可用,因为这个方法将实际数据移动到 for 循环中,并且在其作用域之外不可用。

注意: 默认情况下,for 循环将对集合应用 into_iter() 函数。在使用 for 循环时,我们不必使用 into_iter() 函数将集合转换为迭代器。

例如,以下两种遍历迭代器的方式是相同的。

for color in colors.into_iter() {
// 代码
}

for color in colors {
// 代码
}

3. 使用 iter_mut() 方法

对集合使用 iter_mut() 方法将在每次迭代中可变地借用集合的每个元素。这意味着我们可以就地修改集合。

例如,

fn main() {
let mut colors = vec!["Red", "Yellow", "Green"];

// 使用 iter_mut() 遍历集合
for color in colors.iter_mut() {
// 修改集合中的元素
*color = "Black";
println!("{}", color);
}

// 此处可用的修改后的集合
println!("colors = {:?}", colors);
}

输出

Black
Black
Black
colors = ["Black", "Black", "Black"]

注意,我们在这里使用了 iter_mut() 方法,通过 *color = "Black" 改变集合中的原始项。因此,循环结束后,集合中的每个元素都被修改了。

注意: 构造迭代器的所有方法都遵循 借用 的概念。想了解更多关于借用的信息,请访问 Rust 引用与借用

Rust 中的迭代器适配器

迭代器适配器用于将迭代器转换为另一种迭代器,通过改变其行为。例如,让我们看看 map() 适配器。

let numbers = vec![1, 2, 3];

numbers.iter().map(|i| i + 1);

这里,map() 方法接受一个闭包来对向量 numbers 中的每个项进行调用。

然而,我们必须在 map() 适配器上使用 collect() 方法来收集结果。这是因为迭代器适配器不会直接(惰性地)产生结果,除非调用了 collect() 方法。

numbers.iter().map(|i| i + 1).collect();

这将返回一个向量,其中包含原始向量中的每个项增加 1

示例:迭代器适配器

fn main() {
let numbers: Vec<i32> = vec![1, 2, 3];

// 使用 map 迭代器适配器
let even_numbers: Vec<i32> = numbers.iter().map(|i| i * 2).collect();

println!("numbers = {:?}", numbers);
println!("even_numbers = {:?}", even_numbers);
}

输出

numbers = [1, 2, 3]
even_numbers = [2, 4, 6]

在上述示例中,我们在 numbers 迭代器上使用了 map() 方法来遍历每个项。生成的向量包含原始向量中的每个项乘以 2

Rust 中的范围

创建迭代器的另一种方法是使用范围表示法。一个范围的例子是 1..6,这是一个迭代器。例如,

fn main() {
// 遍历一个范围
for i in 1..6 {
println!("{}", i);
}
}

输出

1
2
3
4
5

这里,我们遍历了一个范围 1..6,它在左侧是包含的(从 1 开始),在右侧是不包含的(结束于 5)。范围通常与 for 循环一起使用。

想了解更多关于范围和 for 循环的信息,请访问 Rust for 循环