在 Rust 中,for...in 循环是遍历集合的核心工具。它看似简单,却暗藏着 Rust 对内存安全和所有权的精妙设计。本文将聚焦 for...in 循环的本质,解析它如何通过迭代器实现灵活的集合遍历,以及不同迭代方式的选择逻辑。
本质:迭代器的“语法糖”
for...in 循环的核心逻辑是迭代一个迭代器(Iterator)。Rust 中所有能被 for...in 遍历的类型(如向量、数组、范围等),都实现了 IntoIterator 特性——这个特性的作用是将类型“转换为迭代器”。
简单说,for item in 集合 本质上是在做:
- 调用集合的
into_iter()方法,将其转换为迭代器; - 依次从迭代器中取出元素,赋值给循环变量
item; - 直到迭代器耗尽,循环结束。
三种基础遍历方式:从引用到所有权
针对集合的不同使用场景(只读、修改、消耗),for...in 有三种典型写法,对应三种迭代器类型:
1. 只读遍历:迭代不可变引用
当你需要访问集合元素但不修改它们时,用 &集合 触发不可变引用迭代:
|
|
这里的 &vec 会通过 IntoIterator 转换为 vec.iter() 返回的迭代器,每次迭代获取的是元素的不可变引用(&T)。由于只借用元素,原集合不会被修改或消耗。
为什么用 iter() 而不是 iter_mut()?
iter() 产生的不可变引用可以共享,不影响其他地方对集合的只读访问。而 iter_mut() 产生的可变引用具有排他性——迭代期间整个集合会被独占借用,其他地方无法同时访问(包括读取)。因此,仅需读取时用 iter() 更灵活。
2. 修改遍历:迭代可变引用
若要修改集合元素,用 &mut 集合 触发可变引用迭代:
|
|
&mut vec 会转换为 vec.iter_mut() 返回的迭代器,每次迭代获取元素的可变引用(&mut T)。通过可变引用,我们可以直接修改集合中的元素,且原集合仍可继续使用。
3. 消耗遍历:迭代所有权
当你需要获取元素的所有权(例如将元素转移到其他地方),直接用 集合 触发所有权迭代:
|
|
直接使用 vec 时,会调用 vec.into_iter() 生成迭代器,每次迭代会将元素的所有权从集合中“取出”并转移给 item。遍历结束后,原集合因失去所有元素的所有权而被“消耗”,无法再被访问。
为什么“不需要修改时,也可能需要消耗遍历?
“不需要修改”仅意味着不需要改变元素的值,但可能需要转移元素的所有权:
- 例如将元素存入另一个集合(需拥有所有权才能存入);
- 对于整数等
Copy类型,消耗遍历可避免反复解引用(直接使用值更简洁); - 处理临时集合时,“用完即弃”可节省内存。
示例:
|
|
特殊场景:范围迭代
除了集合,for...in 还能直接遍历“范围(Range)”,这是一种无需提前创建集合的轻量迭代方式:
|
|
范围本质上也是一种迭代器,它通过计算生成序列,无需占用额外内存。
总结:三种迭代方式的核心区别
| 迭代方式 | 元素类型 | 是否消耗原集合 | 适用场景 |
|---|---|---|---|
iter() |
&T(不可变引用) |
不消耗 | 只读访问,需保留原集合,允许共享访问 |
iter_mut() |
&mut T(可变引用) |
不消耗 | 需要修改元素,独占集合访问权 |
into_iter() |
T(所有权) |
消耗 | 需获取元素所有权(转移、Copy 类型简化操作等),用完即弃集合 |
选择的核心逻辑是:是否需要修改元素,以及是否需要保留原集合。掌握这三种方式,就能灵活应对 Rust 中绝大多数集合遍历场景。