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];
// iterator
let numbers_iterator = numbers.iter();
for number in numbers_iterator {
println!("{}", number);
}
}
输出
2 1 17 99 34 56
这里,`for..in` 循环使用 `numbers_iterator` 中的迭代器进行调用,迭代器中的每个值在一次迭代中使用,然后打印到屏幕上。
Rust 迭代器的 `next()` 方法
迭代器的另一个重要方法是 `next()` 方法。迭代器的 `next()` 方法可用于遍历迭代器中的值。
根据定义,Rust 中的每个迭代器都将具有 `next()` 方法。`next()` 方法用于从迭代器中获取单个值。
我们来看一个例子。
fn main() {
let colors = vec!["Red", "Yellow", "Green"];
// iterator
let mut colors_iterator = colors.iter();
println!("colors iterator = {:?}", colors_iterator);
// fetch values from iterator one by one using next() method
println!("{:?}", colors_iterator.next());
println!("{:?}", colors_iterator.next());
println!("{:?}", colors_iterator.next());
println!("{:?}", colors_iterator.next());
}
输出
colors iterator = 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"];
// using iter() to iterate through a collection
for color in colors.iter() {
// reference to the items in the iterator
println!("{}", color);
}
// the collection is untouched and still available here
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"];
// using into_iter() to iterate through a collection
for color in colors.into_iter() {
// the items in the collection move into this scope
println!("{}", color);
}
// end of scope of for loop
// error
// the collection is not available here as the for loop scope ends above
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 |
这里请注意,`colors` 变量不可用,因为 `into_iter()` 方法将实际数据移动到 `for` 循环中,并且在作用域之外不可用。
注意: 默认情况下,for 循环会将 `into_iter()` 函数应用于集合。在使用 for 循环时,我们不必使用 `into_iter()` 函数将集合转换为迭代器。
例如,遍历迭代器的这两种方式是相同的。
for color in colors.into_iter() {
// code
}
for color in colors {
// code
}
3. 使用 iter_mut() 方法
在集合上使用 `iter_mut()` 方法将在每次迭代中可变地借用集合的每个元素。这意味着我们可以就地修改集合。
例如,
fn main() {
let mut colors = vec!["Red", "Yellow", "Green"];
// using iter_mut() to iterate through a collection
for color in colors.iter_mut() {
// modify the item in the collection
*color = "Black";
println!("{}", color);
}
// the modified collection is available here
println!("colors = {:?}", colors);
}
输出
Black Black Black colors = ["Black", "Black", "Black"]
这里请注意,我们使用 `iter_mut()` 方法通过 `*color = "Black"` 来更改集合中的原始项。因此,for 循环之后集合中的每个项都被修改了。
注意: 所有创建迭代器的方法都遵循 **借用** 的概念。要了解有关借用的更多信息,请访问 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];
// using the map iterator adapter
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() {
// looping through a range
for i in 1..6 {
println!("{}", i);
}
}
输出
1 2 3 4 5
在这里,我们循环遍历范围 `1..6`,该范围在左侧是包含的(从 1 开始),在右侧是排除的(结束于 5)。范围通常与 `for` 循环一起使用。
要了解有关范围和 for 循环的更多信息,请访问 Rust for Loop。