Rust 迭代器

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 中创建迭代器的方法

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

  1. 使用 `iter()` 方法
  2. 使用 `into_iter()` 方法
  3. 使用 `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


我们的高级学习平台,凭借十多年的经验和数千条反馈创建。

以前所未有的方式学习和提高您的编程技能。

试用 Programiz PRO
  • 交互式课程
  • 证书
  • AI 帮助
  • 2000+ 挑战