iter vs into_iter 在 Rust 中:引擎盖下隐藏着什么?

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

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

开始课程

iter vs into_iter:Rust 迭代领域的巅峰对决

\n\n

如果你曾经在 Rust 中编写过遍历向量的循环,你很可能遇到过三个“孪生兄弟”:iter()、into_iter() 和 iter_mut()。乍一看,它们做的事情都一样——让你遍历元素。但它们之间的差异比表面看起来要深刻得多,并且根植于 Rust 的核心——所有权系统。

\n\n

想象一下,你是一名咖啡师,而你的集合就是咖啡豆。iter() 让你观察豆子,闻一闻,但不能触碰。into_iter() 就像你拿起豆子,研磨它们,制作浓缩咖啡,之后豆子就消失了。而 iter_mut() 则是你不仅可以观察,还可以直接在袋子里研磨豆子,改变它们的形态。

\n\n

今天,我们将像 Stack Overflow 上解释的那样,深入剖析 iter vs into_iter,但会结合生动的例子并深入底层原理。我们开始吧!

\n\n

Rust 中的迭代器是什么?

\n\n

迭代器是一个知道如何从集合中顺序获取元素的对象。在 Rust 中,迭代器是惰性的:在你调用 next() 之前,它们什么也不做。但关键在于,每种迭代方法对数据所有权的处理方式不同。

\n\n

以下是三种主要方式:

\n
    \n
  • iter() — 借用元素(不获取所有权)
  • \n
  • into_iter() — 消费集合(获取所有权)
  • \n
  • iter_mut() — 可变借用
  • \n
\n\n

让我们看看代码。假设我们有一个名字的向量:

\n\n
let names = vec!["安娜".to_string(), "鲍里斯".to_string(), "维克多".to_string()];
\n\n

示例 1:iter() — 只看不碰

\n\n
fn main() {\n    let names = vec!["安娜".to_string(), "鲍里斯".to_string(), "维克多".to_string()];\n    \n    // iter() 返回 &String(引用)\n    for name in names.iter() {\n        println!("你好,{}!", name);\n    }\n    \n    // names 仍然可用!\n    println!("向量仍然存在:{:?}", names);\n}
\n\n

注意:循环之后,我们可以放心地使用 names。为什么?因为 iter() 返回了每个元素的引用。所有权仍然属于向量。这是安全且可预测的。

\n\n

示例 2:into_iter() — 破釜沉舟

\n\n
fn main() {\n    let names = vec!["安娜".to_string(), "鲍里斯".to_string(), "维克多".to_string()];\n    \n    // into_iter() 返回 String(所有权被转移)\n    for name in names.into_iter() {\n        println!("再见,{}!", name);\n    }\n    \n    // 错误!names 不再存在\n    // println!("向量仍然存在:{:?}", names); // ❌ 借用了已移动的值\n}
\n\n

这就是关键区别。into_iter() 消费了集合。每个元素都被移入循环,原始向量变得无效。如果你需要保留集合以供后续使用——into_iter() 不是你的选择。

\n\n

示例 3:iter_mut() — 改变而不破坏

\n\n
fn main() {\n    let mut names = vec!["安娜".to_string(), "鲍里斯".to_string(), "维克多".to_string()];\n    \n    // iter_mut() 返回 &mut String(可变引用)\n    for name in names.iter_mut() {\n        name.push_str(" (客人)");\n    }\n    \n    println!("修改后的向量:{:?}", names);\n    // 输出:["安娜 (客人)", "鲍里斯 (客人)", "维克多 (客人)"]\n}
\n\n

这里我们原地修改元素,但不获取所有权。非常适合进行转换操作。

\n\n

底层原理:每个方法返回什么?

\n\n

要真正理解 iter vs into_iter,让我们看看标准库。对于向量 Vec<T>:

\n\n