Rust迭代器
- Rust迭代器基础:在Rust中,迭代器用于创建值的序列,可通过循环遍历,如数组。使用
iter()
方法将数据结构转换为迭代器,允许遍历其元素。 - 迭代器的方法:
next()
方法用于单个值遍历,返回Some
值或到达末尾时返回None
。不同的迭代器创建方法(iter()
,into_iter()
,iter_mut()
)提供不同的数据视图与修改能力。 - 迭代器适配器与范围:迭代器适配器(如
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 中创建迭代器的方法
我们可以通过将集合转换为迭代器来创建迭代器。有三种方法可以创建迭代器。
- 使用
iter()
方法 - 使用
into_iter()
方法 - 使用
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 循环。