跳转到内容

Rust for 循环

for 会逐个遍历一个范围或一个集合里的元素。在 Rust 的三种循环里,这是你最常用的一种。

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

输出:

1
2
3
4
5
▶ 动手试一试

1..=5 是一个包含两端的范围(range),也就是 1 到 5。如果去掉 =,写成 1..5,它就会少一个,只到 4。这种差一的问题很容易踩坑,所以值得再确认一下你想要的是哪一种。

这才是 for 真正出彩的地方——遍历数组或 vector,不用自己管索引:

fn main() {
let fruits = ["苹果", "香蕉", "樱桃"];
for fruit in fruits {
println!("{fruit}");
}
}

输出:

苹果
香蕉
樱桃
▶ 动手试一试

和用 while 循环手动计数、再用索引(fruits[i])取值相比,这种写法更短,也没有会写错的索引。关于数组和 vector,你会在数组和 Vector 这两页学到更多。

如果既需要位置又需要值,就用 .enumerate():

fn main() {
let fruits = ["苹果", "香蕉", "樱桃"];
for (index, fruit) in fruits.iter().enumerate() {
println!("{index}: {fruit}");
}
}

输出:

0: 苹果
1: 香蕉
2: 樱桃
▶ 动手试一试

(index, fruit) 这部分是一个元组模式:每一轮都会给你一对值,循环帮你把它拆成两个变量。

如果想从 3 倒数,或者只访问每隔一个的数,该怎么办?很自然的第一反应是写一个倒过来的范围,比如 3..=1。它能编译,但循环一次都不会执行。范围只会往上数,起点比终点大的范围就是空的。

正确的做法是:用一个正常的范围,然后改变遍历它的方式:

  • .rev() 倒序遍历这个范围。
  • .step_by(n) 从第一个值开始,每隔 n 个取一个值。
fn main() {
for i in (1..=3).rev() {
println!("{i}...");
}
println!("出发!");
for even in (0..=10).step_by(2) {
print!("{even} ");
}
println!();
for i in 3..=1 {
println!("这行永远不会打印:{i}");
}
}

输出:

3...
2...
1...
出发!
0 2 4 6 8 10
▶ 动手试一试

注意括号:(1..=3).rev()。如果不加括号,Rust 会把 1..=3.rev() 理解成“从 1 到 3.rev()”,这可不是你想要的。两者也可以组合使用:(0..=10).rev().step_by(5) 会得到 10、5、0。

为什么计数时更推荐 for 而不是 while

Section titled “为什么计数时更推荐 for 而不是 while”

计数循环也可以用 while 写,但用 for 加范围,能一下子消除一整类错误——没有需要手动更新、可能被忘掉的计数器,也不会多走一步越过数组的末尾。Rust 程序员默认用 for,只有在没有现成的范围或集合可遍历时才用 while。

打印 7 的乘法表,从 7 x 1 = 7 到 7 x 10 = 70。提示:一个遍历 1..=10 的 for 循环就够了。乘法可以直接写在 println! 里。

查看答案
fn main() {
for i in 1..=10 {
println!("7 x {i} = {}", 7 * i);
}
}

输出:

7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
7 x 6 = 42
7 x 7 = 49
7 x 8 = 56
7 x 9 = 63
7 x 10 = 70
▶ 动手试一试

像 {i} 这样的具名变量可以直接写进花括号里。而像 7 * i 这样的计算不行,所以要用一个空的 {},再把值写在逗号后面。

把 1 到 99 之间的所有奇数加起来,并打印总和。提示:(1..100).step_by(2) 会给你 1、3、5……99。在循环外面放一个 mut 的总和变量。

查看答案
fn main() {
let mut total = 0;
for n in (1..100).step_by(2) {
total += n;
}
println!("1 到 99 的奇数加起来是 {total}");
}

输出:

1 到 99 的奇数加起来是 2500
▶ 动手试一试

另一种写法是遍历 1..100,只在 n % 2 == 1 时才加上 n。两种都行,只不过 step_by 直接跳过了偶数,而不是一个个去检查。

  • for item in range_or_collection { ... } 是 Rust 里最日常的循环。
  • 1..=5 包含两端;1..5 到 5 之前就停下了。
  • 直接遍历数组或 vector,不用手动写索引就能拿到每个值。
  • 需要索引和值一起用时,用 .enumerate()。
  • 像 3..=1 这样倒过来的范围是空的。倒数用 (1..=3).rev(),跳着数用 .step_by(n)。

小测验

1. 在 for 循环里,1..=5 和 1..5 有什么区别?

2. 遍历集合时,怎样同时拿到索引和值?

3. 为什么遍历集合计数时,一般更推荐用 for 而不是 while?

4. for i in 5..=1 { ... } 会做什么?

得分: 0 / 4