首页 / Rust 入门教程 / for 循环与区间

Rust 入门教程

for 循环与区间

本教程共 78 篇 · 第 19 篇 · 更新于 2026-08-08 · 约 9 分钟阅读

RustRust 入门教程for区间rangerevenumerate迭代器

本节目标:用 for 循环遍历区间和数组,分清 ....= 含不含结尾,掌握 rev() 倒序和 enumerate() 带下标,并理解为什么 for 比手写 while 计数更安全。

前面两种循环都得你手动管”从几到几、怎么步进”。而日常最多的需求是”把 1 到 10 挨个过一遍”或”把数组每个元素处理一下”。Rust 的 for 循环专为这类”遍历”而生,而且几乎不会写出死循环。它被称为 Rust 循环里的”明珠”,是日常用得最频繁的一种。

19-1 for 遍历区间

区间(range)用 a..b 表示”从 a 到 b,不含 b”:

fn main() {
    for i in 1..4 {
        println!("i = {i}");
    }
}

输出是 i = 1i = 2i = 3。注意:1..4 包含 1、2、3,不包含 4。这种”左闭右开”是很多语言的惯例(比如 Python 的 range),记住”右边那个数不参与”。for i in 1..4 读作”对于 1 到 4(不含 4)之间的每个 i”。

19-2 含尾区间 ..=

如果你想把结尾也包含进去,用 ..=

for i in 1..=4 {
    println!("i = {i}");
}

这次输出 1、2、3、4,4 也进来了。..= 读作”到且包含”。新手常搞混该用哪个,记一句:想”打到 4 为止且含 4”就用 ..=4

Warning

1..41..=4 是两种不同的区间,覆盖的元素个数不同。写循环边界时想清楚”最后一个要不要用”。比如要数 1 到 100(都含),写成 1..=100,别漏成 1..100 少算了 100。这种”边界差一个”的 bug 不会报错,但结果会悄悄错。

19-3 for 遍历数组

for 最直接的用途是遍历集合,比如数组:

fn main() {
    let a = [10, 20, 30, 40];
    for element in a {
        println!("元素是 {element}");
    }
}

for element in a 把数组每个元素依次绑到 element。这比 while 手动维护下标安全——你不可能越界,因为 for 只在”确实有元素”时进循环体。对实现了 Copy 的数组(如 [i32; 4]),for element in a 不会移动 a,循环后 a 仍可用。

Note

这正是 forwhile 计数优越的地方:while 要你写 i += 1 并小心边界,漏了就死循环或漏元素;for 直接”对每个元素做一次”,边界由编译器保证,几乎不可能出错。所以 Rust 社区首选 for 做遍历。

这里还有一个关于所有权的小知识点:当你写 for element in collection(collection 是 StringVec 这类堆上的集合)时,所有权会被移动到循环里,循环结束后 collection 就不能再用了。如果你还想在循环后继续使用它,就得写成 for element in &collection(借不可变引用)或 for element in &mut collection(借可变引用去改元素)。而对纯 Copy 类型的数组(如 [i32; 4]),for element in a 只是复制,循环后 a 仍可用。初学者遇到”value moved”报错,往往就是这里没加 &

19-4 倒序:rev()

想反过来数?用 .rev() 把区间颠倒:

for i in (1..=5).rev() {
    println!("{i}");
}

输出 5、4、3、2、1。(1..=5).rev() 生成一个倒过来的序列。括号不能省——.rev() 是作用在区间上的方法,要先有区间再 revfor i in (1..=5).rev() 是倒计时的经典写法。

19-5 带下标的遍历:enumerate

有时你既想要元素、也想要它的位置(第几个):

let a = ["a", "b", "c"];
for (index, value) in a.iter().enumerate() {
    println!("第 {index} 个是 {value}");
}

enumerate() 把每个元素变成 (下标, 值) 的元组,再用解构 (index, value) 一次接住。下标从 0 开始。打印数组又想知道位置时用它,比自己维护计数器优雅,也不会出错。

19-6 用 0..len 做下标遍历

区间是连续整数序列,能配合很多场景。比如用 0..a.len() 拿到”合法下标区间”,绝不会越界:

let a = [10, 20, 30];
for i in 0..a.len() {
    println!("a[{}] = {}", i, a[i]);
}

a.len() 返回数组长度(usize 类型),0..a.len() 就是”合法下标区间”。这比 while 计数直观且安全,因为边界由 a.len() 给出,不会写错。

Tip

凡是”已知次数 / 遍历集合”,一律优先 for。新手的很多数组越界 bug 来自手写 while 下标,换成 for 遍历元素(或 0..len)就根除了。这是 Rust 鼓励的安全写法。

19-7 不关心值时的 _ 占位

有时你只想”重复 N 次”,根本不关心那个循环变量。这时用 _ 占位,既清晰又避免”变量未使用”的编译警告:

for _ in 0..3 {
    println!("倒计时预备……");
}

_ 告诉编译器”我故意不用这个值”。如果不写 _ 而写 for i in 0..3,编译器会警告 i 未被使用。这个小习惯让代码更干净。

19-8 for 遍历一切可迭代物

for 配合区间已经很强,但日常你更多是在”遍历集合”。除了数组,后面会学到的 Vec、字符串、以及很多标准库类型,都能用 for 遍历,因为它们都实现了”迭代器(Iterator)“能力。一句话:凡是能一个一个拿出元素的东西,基本都能 for x in 它

迭代器还有个常用方法 .enumerate()(带下标遍历),以及链式处理(比如”只处理偶数”用过滤),后者属于进阶写法,这里不展开。先记住 .rev() 倒序和 .enumerate() 带下标这两个最实用的。

Note

一个易混点:区间 0..5 是”产生数字 0 到 4 的迭代器”,而数组 [1,2,3] 是”具体的多个值”。两者都能被 for 消费,但本质不同:区间在循环时才逐个算出来,数组是已经存在的内存。理解这点,你就不会困惑”为什么有的东西能 for、有的不能”——关键看它是否”可迭代”。

19-9 for 遍历时别改原集合

for 遍历时如果同时修改集合(比如遍历数组时往里加元素),Rust 会拒绝,因为它要保证遍历期间集合不被破坏。这是安全设计不是限制。真要边遍历边改,通常用 while + 下标、或先收集到新集合再替换。现阶段记住”for 遍历期间别改原集合”即可。

19-10 一个对照表:for 的几种形态

把上面零散的点汇成一张表,方便你随时查:

写法含义遍历后原集合
for x in c移动所有权(堆集合)不可再用
for x in &c不可变借用,只读仍可用
for x in &mut c可变借用,可改元素仍可用
for (i, x) in c.iter().enumerate()带下标遍历c 是否加 &
for _ in 0..n只重复 n 次无关

记住这张表,你基本就掌握了 for 的绝大部分用法。

19-11 你可能会踩的坑

把几个高频错误集中说一下,省得你逐个撞:

  • 坑一:边界差一个1..100 漏算了 100,要含尾写 1..=100。这种错不报错、结果悄悄少一个,最难查。
  • 坑二:忘了加 & 导致集合被移动。遍历 Vec/String 后还想用,却写 for x in v 而非 for x in &v,结果编译器报 “value moved”。
  • 坑三:循环变量没用却写个名字,比如 for i in 0..3 实际没用 i,换来一条”未使用变量”警告。改成 for _ in 0..3 就干净。
  • 坑四:rev 漏括号,写 for i in 1..=5.rev() 会解析出错。.rev() 是作用在区间上的方法,记得用括号包住区间:(1..=5).rev()
Note

for 循环的本质是”消费一个迭代器”。区间、数组、Vec、字符串之所以都能被 for 遍历,是因为它们都实现了 IntoIterator。现阶段你不用深究 trait,只要记住”凡是能一个个拿出元素的东西,基本都能直接 for”就够了。学到迭代器那章,这套机制会完全展开。

19-12 小结

for x in 集合/区间 是最安全的遍历方式;a..b 不含 b,a..=b 含 b;.rev() 倒序;enumerate() 带下标;不关心值时用 _ 占位。遍历数组不用手写下标,几乎不会越界。到这,控制流三件套(if / loop / while / for)齐了。下一章进入全书的核心难点——所有权(Ownership),它是 Rust 内存安全的根基,请打起精神。