在 Rust 中带索引迭代 Vec:4 种方法对比

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

在 Rust 中带索引迭代 Vec:从新手到专家



想象一下:你用 Rust 编写代码,需要遍历向量的元素,但不仅要知道值,还要知道它的位置。看似简单的任务,却常常让新手感到困惑。Python 中的 for i in range(len(vec)) 在哪里?如果我想修改元素呢?哪种方法更快?



在本文中,我们将介绍 在 Rust 中带索引迭代 Vec 的所有流行方法,比较它们的性能、可读性和安全性。您将了解在 2024 年应该选择哪种方法,以及为什么 enumerate 并不总是万能药。



为什么这很重要?

Rust 没有像 for i in 0..vec.len() 这样唯一正确的方式。该语言提供了多种范式:从函数式迭代器到底层循环。理解它们之间的差异是编写高效且惯用代码的关键。在处理 向量 时尤其重要,因为索引可能用于修改相邻元素或跟踪算法中的位置。



方法 1:经典方法 —— enumerate

最常用且推荐的方法。enumerate 方法包装迭代器,为每个元素添加其索引:



let vec = vec!["a", "b", "c", "d"];for (index, value) in vec.iter().enumerate() {    println!("位置 {}: {}", index, value);}


优点:

  • 惯用且可读性强
  • 安全 —— 没有越界风险
  • 适用于任何迭代器,不仅仅是 Vec

缺点: 不能直接修改向量元素(需要 iter_mut())。



方法 2:按索引 —— 0..vec.len()

熟悉 C++ 或 Python 的人都会采用这种方法。使用索引范围:



let mut vec = vec![10, 20, 30, 40];for i in 0..vec.len() {    vec[i] += i; // 按索引修改元素    println!("vec[{}] = {}", i, vec[i]);}


优点:

  • 完全控制索引和元素
  • 可以通过 vec[i] 修改元素
  • 对新手直观易懂

缺点: 比迭代器慢(额外的边界检查)。Rust 社区认为它“不惯用”。



方法 3:带计数器的 while 循环

最“手动”的方式,您会在旧代码或优化中看到:



let vec = vec![1.0, 2.0, 3.0];let mut i = 0;while i < vec.len() {    println!("元素 {}: {}", i, vec[i]);    i += 1;}


优点: 最大的灵活性(可以跳跃索引、改变步长)。

缺点: 容易在条件上出错。没有充分理由不建议使用。



方法 4:带范围的 zip

函数式方法,当需要并行迭代两个向量并带索引时使用:



let names = vec!["Alice", "Bob", "Charlie"];let scores = vec![95, 87, 92];

for (i, (name, score)) in (0..).zip(names.iter()).zip(scores.iter()) { println!("{}: {} 得了 {} 分", i, name, score);}


优点: 适用于并行迭代。无限范围 0.. 会自动截断。

缺点: 可能难以阅读。对于简单任务来说过于复杂。



性能对比

我们在一个包含 100,000 个元素的向量上运行了基准测试(使用 --release 优化):



博客

书籍推荐

方法时间 (ns)相对速度
enumerate~12,0001.0x(基准)
0..len~15,000慢 1.25x