《Rust编程入门》8.2 迭代器与迭代器适配器

8.2 迭代器与迭代器适配器 在 Rust 中,迭代器是一个非常强大的特性,它允许你以一致的方式访问集合中的元素。Rust 的迭代器是懒惰的,这意味着它们不会立即执行,而是会在需要时按需计算。这使得迭代器非常高效,特别是在处理大型集合时。

8.2 迭代器与迭代器适配器

在 Rust 中,迭代器是一个非常强大的特性,它允许你以一致的方式访问集合中的元素。Rust 的迭代器是懒惰的,这意味着它们不会立即执行,而是会在需要时按需计算。这使得迭代器非常高效,特别是在处理大型集合时。

8.2.1 迭代器基础

迭代器是实现了 Iterator 特征的类型。Iterator 特征提供了一个核心方法 next(),它返回一个 Option<T>,每次调用都会返回集合中的下一个元素,直到没有元素可供迭代。

创建一个简单的迭代器

fn main() {
    let v = vec![1, 2, 3, 4, 5];

    let mut iter = v.iter();  // 创建一个迭代器

    // 使用 next() 获取元素
    while let Some(&val) = iter.next() {
        println!("{}", val);  // 输出: 1 2 3 4 5
    }
}
  • v.iter() 返回一个迭代器,它可以遍历 Vec 中的元素。
  • next() 每次调用返回一个 Option 类型,如果迭代器中还有元素,next() 会返回 Some(value);如果没有元素,则返回 None

使用 for 循环简化迭代

fn main() {
    let v = vec![1, 2, 3, 4, 5];

    // 使用 for 循环自动迭代
    for val in v.iter() {
        println!("{}", val);  // 输出: 1 2 3 4 5
    }
}
  • 在 Rust 中,for 循环可以自动处理迭代器,省去了手动调用 next() 的麻烦。

消费者方法:sum()

Rust 提供了一些常用的迭代器方法,可以对集合进行操作并返回最终结果。sum() 是其中之一,它可以对迭代器中的所有元素进行求和。

fn main() {
    let v = vec![1, 2, 3, 4, 5];

    let sum: i32 = v.iter().sum();
    println!("Sum: {}", sum);  // 输出: Sum: 15
}
  • sum() 通过迭代器计算集合中元素的总和。

8.2.2 迭代器适配器

迭代器适配器是链式方法,可以对迭代器执行转换、过滤和其他操作。迭代器适配器本身并不立即执行,而是返回一个新的迭代器,只有在实际遍历时,所有操作才会生效。

map 适配器

map 适配器可以将一个闭包应用到每个元素上,生成新的元素。例如,可以对每个数字进行平方操作:

fn main() {
    let v = vec![1, 2, 3, 4, 5];

    let squares: Vec<i32> = v.iter().map(|&x| x * x).collect();
    println!("{:?}", squares);  // 输出: [1, 4, 9, 16, 25]
}
  • map 返回一个新的迭代器,其中每个元素都经过闭包的处理。
  • collect() 方法用于将迭代器的结果收集到一个集合中(此例中是 Vec<i32>)。

filter 适配器

filter 适配器根据给定的条件过滤元素。例如,只保留偶数:

fn main() {
    let v = vec![1, 2, 3, 4, 5];

    let even_numbers: Vec<i32> = v.iter().filter(|&&x| x % 2 == 0).collect();
    println!("{:?}", even_numbers);  // 输出: [2, 4]
}
  • filter 接受一个闭包,只有返回 true 的元素会被保留。
  • 这里的闭包 |&&x| x % 2 == 0 用于筛选偶数。

takeskip 适配器

  • take 适配器会从迭代器中返回前 n 个元素。
  • skip 适配器会跳过迭代器中的前 n 个元素,返回剩余部分。
fn main() {
    let v = vec![1, 2, 3, 4, 5];

    let first_three: Vec<i32> = v.iter().take(3).collect();
    let after_first_two: Vec<i32> = v.iter().skip(2).collect();

    println!("{:?}", first_three);      // 输出: [1, 2, 3]
    println!("{:?}", after_first_two);  // 输出: [3, 4, 5]
}
  • take(3) 选择前 3 个元素。
  • skip(2) 跳过前 2 个元素,返回剩余部分。

fold 适配器

fold 适配器是一个非常强大的方法,它允许你对迭代器中的元素进行累计操作,返回一个最终结果。与 reduce 类似,它从初始值开始,逐步应用闭包中的操作。

fn main() {
    let v = vec![1, 2, 3, 4, 5];

    let sum: i32 = v.iter().fold(0, |acc, &x| acc + x);
    println!("Sum using fold: {}", sum);  // 输出: Sum using fold: 15
}
  • fold(0, |acc, &x| acc + x)0 开始,累加每个元素的值。

zip 适配器

zip 适配器用于将两个迭代器“压缩”成一个新的迭代器,其中每个元素是一个元组,包含两个原始迭代器的元素。

fn main() {
    let v1 = vec![1, 2, 3];
    let v2 = vec![4, 5, 6];

    let zipped: Vec<(i32, i32)> = v1.iter().zip(v2.iter()).collect();
    println!("{:?}", zipped);  // 输出: [(1, 4), (2, 5), (3, 6)]
}
  • zip 将两个迭代器中的元素配对成元组。

8.2.3 迭代器的惰性计算

Rust 中的迭代器是惰性(lazy)的,意味着它们不会立即执行。只有当我们真正遍历它们时,才会进行计算。通过这种方式,Rust 能够避免不必要的计算,提高性能。

例如,下面的代码展示了 mapfilter 适配器的惰性特性:

fn main() {
    let v = vec![1, 2, 3, 4, 5];

    // 创建一个链式迭代器
    let result: Vec<_> = v.iter().map(|&x| x * 2).filter(|&x| x > 5).collect();
    println!("{:?}", result);  // 输出: [6, 8, 10]
}
  • 在执行时,mapfilter 会依次处理元素,但没有立即产生结果,直到调用 collect() 才会进行所有的计算。

8.2.4 小结

  • 迭代器是 Rust 中的核心特性,它允许以一致的方式访问集合中的元素,并提供了多种常用操作。
  • Rust 的迭代器是惰性求值的,只有在实际遍历时才会执行计算,这有助于提高性能。
  • 迭代器适配器(如 mapfilterfold 等)可以对迭代器进行转换,返回一个新的迭代器,使得处理数据的方式更加灵活。

在下一节中,我们将深入探讨闭包与高阶函数,它们与迭代器和迭代器适配器紧密结合,进一步提升 Rust 的表达力和灵活性。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页