Rust: Rust 循环与迭代:loop、while、for 全掌握

最后更新:2026-08-26

Rust 的 loop 不是简单的"死循环"——它能把最后一次计算的值"吐"出来。

三种循环各有各的用武之地:loop 无限循环(可返回值)、while 条件循环、for 集合遍历。


1. 你将学到


2. 一个迷宫探索者的故事

(1) 痛苦:在迷宫中迷路

Alex 在开发一款迷宫游戏。迷宫有三层嵌套结构:

TEXT 📖 仅展示
外层(地牢)→ 中层(房间)→ 内层(宝箱)

玩家需要逐层深入找出口,但他发现代码很难写:

"如果能给每一层循环贴上标签,想跳哪里就跳哪里就好了……"

(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. 三种循环对比

100%
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

没有标签时,breakcontinue 只作用于最内层循环。加上标签('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 考虑把内层循环提取成函数。

📖 小节


📝 作业

  1. 难度 ⭐:用 for 循环遍历 0..=10,只打印偶数(用 if i % 2 == 0 判断)。
  2. 难度 ⭐⭐:用 loop + break 返回值模拟:从 vec![1, 3, 5, 7, 9, 11] 中找到第一个大于 6 的值并返回,找不到返回 -1。
  3. 难度 ⭐⭐⭐:用双层 for 循环打印 9x9 乘法表,要求每行输出 1x1=1 1x2=2 … 格式。思考如何用循环标签控制换行逻辑。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏