Rust: Rust 循环与迭代:loop、while、for 全掌握
最后更新:2026-08-26
Rust 的 loop 不是简单的"死循环"——它能把最后一次计算的值"吐"出来。
三种循环各有各的用武之地:loop 无限循环(可返回值)、while 条件循环、for 集合遍历。
1. 你将学到
- 用
loop创建无限循环并返回值 - 用
while做条件循环 - 用
for遍历集合和范围 - 用
break和continue控制循环流程 - 用循环标签跳出嵌套循环
- 用范围表达式
0..n和0..=n
2. 一个迷宫探索者的故事
(1) 痛苦:在迷宫中迷路
Alex 在开发一款迷宫游戏。迷宫有三层嵌套结构:
TEXT
📖 仅展示
外层(地牢)→ 中层(房间)→ 内层(宝箱)
玩家需要逐层深入找出口,但他发现代码很难写:
- 在宝箱里找到钥匙后,想跳出到房间层——但
break只能跳出一层 - 要找遍所有房间才能开门——用
while还是for? - 迷宫的层数是固定的—但每层房间数量不同
"如果能给每一层循环贴上标签,想跳哪里就跳哪里就好了……"
(2) Rust 的循环解决方案
RUST
fn main() {
let mut found_exit = false;
let maze = [
["empty", "empty", "key"],
["empty", "monster", "empty"],
["exit", "empty", "trap"],
];
// 外层标签 'outer 给地牢循环命名
'outer: for (row, floor) in maze.iter().enumerate() {
println!("进入地牢第 {} 层", row + 1);
for (col, room) in floor.iter().enumerate() {
match *room {
"exit" => {
println!(" 找到出口!位置: ({}, {})", row, col);
found_exit = true;
break 'outer; // 直接跳出两层循环
}
"key" => println!(" 拿到钥匙 (位置: {},{})", row, col),
"monster" => println!(" 有怪物!跳过这个房间"),
_ => println!(" 空房间 {}", col),
}
}
}
println!("是否找到出口: {}", found_exit);
}
Rust 的循环标签(
'outer)让break可以跳出任意层级的循环。这比goto更安全——它不会跳转到代码的任意位置,只跳出循环。
3. 三种循环对比
graph TB
A[Rust 循环] --> B[loop: 无限循环]
A --> C[while: 条件循环]
A --> D[for: 集合遍历]
B --> E[直到 break 为止]
B --> F[可用 break 返回值]
C --> G[每次循环前检查条件]
D --> H[自动遍历集合/范围]
D --> I[最常用、最安全]
| 特性 | loop |
while |
for |
|---|---|---|---|
| 何时用 | 不确定结束条件 | 条件驱动 | 遍历集合或范围 |
| 返回值 | break value 可带返回值 |
不能返回值 | 不能返回值 |
| 无限循环 | 原生 | while true |
不适合 |
| 性能 | 最优(编译器知道会循环) | 略差(每次检查条件) | 最优(迭代器直接驱动) |
| 应用场景 | 重试/轮询 | 条件等待 | 遍历数组/向量/范围 |
(2) break 与 continue 对比
| 关键字 | 作用 | 可带返回值 | 配合标签 |
|---|---|---|---|
break |
跳出当前循环 | break value;(仅 loop) |
break 'label; |
continue |
跳过本次循环剩余部分 | 不能 | continue 'label; |
(3) 范围表达式
| 写法 | 含义 | 包含结束值 | 示例 |
|---|---|---|---|
start..end |
半开区间 | 否 | 0..5 → 0,1,2,3,4 |
start..=end |
闭区间 | 是 | 0..=5 → 0,1,2,3,4,5 |
..end |
从 0 到 end | 否 | ..3 → 0,1,2 |
start.. |
从 start 到末尾 | — | 3.. → 3,4,5,... |
4. 循环示例
▶ 示例 1:loop 无限循环与 break 返回值(难度 ⭐)
RUST
// ============================================
// loop 循环:模拟猜数字游戏的"再来一次"
// ============================================
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 5 {
break counter * 2; // break 可以带返回值!
}
};
println!("循环执行了 5 次,break 返回: {}", result);
// 实用场景:反复重试直到成功
let mut attempts = 0;
let success = loop {
attempts += 1;
if attempts >= 3 {
break true;
}
// 模拟某操作失败,继续重试
};
println!("重试 {} 次后成功: {}", attempts, success);
}
输出:
TEXT
📖 仅展示
循环执行了 5 次,break 返回: 10
重试 3 次后成功: true
loop是 Rust 唯一可以返回值的循环结构。break关键字后面可以直接跟返回值,不需要额外变量。这在"尝试直到成功"模式中非常实用。
▶ 示例 2:while 条件循环(难度 ⭐)
RUST
// ============================================
// while 循环:递减倒计时
// ============================================
fn main() {
let mut countdown = 5;
while countdown > 0 {
println!("倒计时: {}...", countdown);
countdown -= 1;
}
println!("发射!");
}
输出:
TEXT
📖 仅展示
倒计时: 5...
倒计时: 4...
倒计时: 3...
倒计时: 2...
倒计时: 1...
发射!
while在每次循环开始前检查条件。如果条件为false,跳过整个循环体。适合"不知道需要循环多少次但知道终止条件"的场景。
▶ 示例 3:for 遍历与范围(难度 ⭐⭐)
RUST
// ============================================
// for 循环:遍历范围、数组和字符串
// ============================================
fn main() {
// 1. 范围遍历:0..5 是 0 到 4(不含 5)
println!("-- 范围 0..5 --");
for i in 0..5 {
print!("{} ", i);
}
println!();
// 2. 闭合范围:0..=5 包含 5
println!("-- 范围 0..=5 --");
for i in 0..=5 {
print!("{} ", i);
}
println!();
// 3. 遍历数组
let fruits = ["apple", "banana", "cherry"];
println!("-- 水果列表 --");
for fruit in &fruits {
println!("{}", fruit);
}
// 4. 带索引的遍历(enumerate)
println!("-- 带索引的遍历 --");
for (index, fruit) in fruits.iter().enumerate() {
println!("水果 #{}: {}", index, fruit);
}
}
输出:
TEXT
📖 仅展示
-- 范围 0..5 --
0 1 2 3 4
-- 范围 0..=5 --
0 1 2 3 4 5
-- 水果列表 --
apple
banana
cherry
-- 带索引的遍历 --
水果 #0: apple
水果 #1: banana
水果 #2: cherry
for是 Rust 中最推荐使用的循环方式。它不会越界,自动处理迭代。0..n是半开区间(不含 n),0..=n是闭区间(含 n)。.enumerate()给每个元素加上索引。
▶ 示例 4:循环标签与嵌套循环(难度 ⭐⭐⭐)
RUST
// ============================================
// 循环标签:break 'label 跳出多层嵌套
// ============================================
fn main() {
let matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
let mut found = 0;
// 'search 标签标记外层循环
'search: for (i, row) in matrix.iter().enumerate() {
for (j, &val) in row.iter().enumerate() {
if val == 5 {
println!("找到目标 5 在位置 ({}, {})", i, j);
found = val;
break 'search; // 直接跳出两层循环!
}
}
}
println!("找到的值: {}", found);
// continue 也可以配合标签使用
'outer: for x in 0..3 {
for y in 0..3 {
if x == y {
continue 'outer; // 跳过内层剩余,继续外层下一个
}
println!("x={}, y={}", x, y);
}
}
}
输出:
TEXT
📖 仅展示
找到目标 5 在位置 (1, 1)
找到的值: 5
x=1, y=0
x=2, y=0
x=2, y=1
没有标签时,
break和continue只作用于最内层循环。加上标签('name),你可以控制任意层级的循环。这是一种比goto更受控制的"跳出"方式。
▶ 示例 5:综合练习——FizzBuzz 与九九乘法表(难度 ⭐⭐)
RUST
// ============================================
// 综合循环实战:FizzBuzz + 九九乘法表
// ============================================
fn main() {
println!("=== FizzBuzz (1-30) ===");
for n in 1..=30 {
match (n % 3, n % 5) {
(0, 0) => print!("FizzBuzz "),
(0, _) => print!("Fizz "),
(_, 0) => print!("Buzz "),
_ => print!("{} ", n),
}
if n % 10 == 0 { println!(); }
}
println!();
println!("\n=== 九九乘法表 ===");
for i in 1..=9 {
for j in 1..=i {
print!("{}×{}={:<4}", j, i, i * j);
}
println!();
}
println!("\n=== while let 模拟读取 ===");
let mut queue = vec![10, 20, 30, 40, 0];
while let Some(item) = queue.pop() {
if item == 0 {
println!("遇到终止信号,停止处理");
break;
}
println!("处理项目: {}", item);
}
println!("\n=== loop 重试模式 ===");
let attempts = try_connect(3);
println!("连接结果: {}", attempts);
}
fn try_connect(max_retries: u32) -> bool {
let mut attempt = 0;
loop {
attempt += 1;
println!("第 {} 次尝试连接...", attempt);
if attempt >= max_retries {
break true;
}
}
}
输出:
TEXT
📖 仅展示
=== FizzBuzz (1-30) ===
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz
11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz
Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz
=== 九九乘法表 ===
1×1=1
1×2=2 2×2=4
1×3=3 2×3=6 3×3=9
1×4=4 2×4=8 3×4=12 4×4=16
1×5=5 2×5=10 3×5=15 4×5=20 5×5=25
1×6=6 2×6=12 3×6=18 4×6=24 5×6=30 6×6=36
1×7=7 2×7=14 3×7=21 4×7=28 5×7=35 6×7=42 7×7=49
1×8=8 2×8=16 3×8=24 4×8=32 5×8=40 6×8=48 7×8=56 8×8=64
1×9=9 2×9=18 3×9=27 4×9=36 5×9=45 6×9=54 7×9=63 8×9=72 9×9=81
=== while let 模拟读取 ===
处理项目: 40
处理项目: 30
处理项目: 20
处理项目: 10
遇到终止信号,停止处理
=== loop 重试模式 ===
第 1 次尝试连接...
第 2 次尝试连接...
第 3 次尝试连接...
连接结果: true
FizzBuzz 用
match元组模式匹配更优雅;九九乘法表用双层for+ 范围区间;while let适合处理"取到值就继续"的循环模式;loop+break适合重试逻辑。
❓ 常见问题
Q loop 和 while true 有什么区别?
A loop 是 Rust 首选。
Q for i in 0..n 和 for i in 0..=n 有什么区别?
A .. 是半开区间(不含 n),..= 是闭区间(含 n)。
Q for 遍历数组时,&fruits 和 fruits.iter() 有什么区别?
A &fruits 隐式调用 into_iter 借用元素,fruits.iter() 显式更清晰。
Q break 返回值怎么用?
A loop 的 break 可以像函数一样返回值:
let x = loop { break 42; };。Q 嵌套循环太多怎么办?
A 考虑把内层循环提取成函数。
📖 小节
loop:无限循环,可以用break value返回值while:条件循环,每次循环前检查条件for:集合/范围遍历,最推荐使用- 范围表达式:
0..5(不含 5)、0..=5(含 5) - 循环标签
'label可以跳出/跳过任意层级循环 break跳出循环,continue跳过本次循环剩余部分
📝 作业
- 难度 ⭐:用
for循环遍历0..=10,只打印偶数(用if i % 2 == 0判断)。 - 难度 ⭐⭐:用
loop+break返回值模拟:从 vec![1, 3, 5, 7, 9, 11] 中找到第一个大于 6 的值并返回,找不到返回 -1。 - 难度 ⭐⭐⭐:用双层
for循环打印 9x9 乘法表,要求每行输出1x1=1 1x2=2 …格式。思考如何用循环标签控制换行逻辑。