blog.dopana

Back

在 Rust 中,循环不仅是代码重复执行的工具,更是兼具强大表现力的控制流结构。除了基础的 forwhile 之外,Rust 还提供了可以返回值的 loop 表达式、与模式匹配深度结合的 while let、以及精细控制多层嵌套的循环标签。

像给 10 岁孩子解释:自动售货机与弹簧糖果盒#

想象两种不同的小零食获取机制:

  1. 自动售货机 (loopbreak 奖励): 你不断投币重试直到中奖;一旦满足中奖条件,机器立刻将奖品直接吐到你手里(break 奖品)。
  2. 皮礼士糖果盒 (while let Some(糖果)): 每次你把盒子头部向后掰开,都检查是否有糖果冒出来。只要能推出糖果(Some(糖果)),你就吃掉它。当糖果盒彻底空了(None),循环就自然终止。
graph TD
    Start["开始循环"] --> PatternMatch{"表达式是否匹配模式?<br/>(例如: Some(item))"}
    PatternMatch -->|是: 提取 item| LoopBody["使用 item 执行循环体"]
    LoopBody --> NextEval["评估下一个元素 / 状态"]
    NextEval --> PatternMatch
    PatternMatch -->|否: None / 不匹配| Terminate["安全退出循环"]

loop 表达式:直接返回值#

在很多 C 风格语言中,循环仅是语句(statement);而在 Rust 中,loop 是一个表达式(expression)。你可以给 break 传递一个值,将其作为整个循环的计算结果返回:

graph LR
    LStart["进入 loop"] --> Work["执行重试逻辑"]
    Work --> Check{"是否达到成功条件?"}
    Check -->|否| Work
    Check -->|是: break value| ReturnVal["result = 返回的值"]

while let:只要模式匹配就持续循环#

当需要从栈、队列、通道(Channel)或迭代器中持续提取数据时,传统写法需要冗长的解包代码。while let 能够在模式持续匹配的前提下执行循环体:

冗长写法(使用 loop + match#

src/main.rs
let mut stack = vec![1, 2, 3];

loop {
    match stack.pop() {
        Some(top) => println!("弹出元素: {top}"),
        None => break, // 栈空时退出
    }
}
rust

使用 while let 的惯用写法#

src/main.rs
let mut stack = vec![1, 2, 3];

// 只要 stack.pop() 返回 Some(top) 就一直循环
while let Some(top) = stack.pop() {
    println!("弹出元素: {top}");
}
rust

[!TIP] 凡是涉及到持续消费 OptionResult 数据流(如从通道读取消息 receiver.recv())直到遇到 NoneErr 的场景,优先选用 while let

循环标签(Loop Labels):精准控制多层嵌套#

当存在多层嵌套循环时,默认的 breakcontinue 只作用于最内层循环。你可以为外层循环指定一个循环标签(以单引号 ' 开头),从而实现跨层跳出:

sequenceDiagram
    participant Outer as 外层循环
    participant Inner as 内层循环
    
    Outer->>Inner: 进入内层循环
    Inner->>Inner: remaining == 9: break 内层
    Inner-->>Outer: 返回外层循环
    Outer->>Inner: 再次进入内层循环 count 为 2
    Inner->>Outer: break counting_up: 彻底跳出外层循环

Rust 各循环结构特性对比#

结构主要适用场景支持 break 返回值模式匹配支持?
loop无限循环、重试机制、工作线程支持内部可配合 match
while 条件常规布尔条件循环不支持不支持
while let 模式持续消费 Option / Result 序列不支持支持(自动绑定局部变量)
for 元素 in 迭代器遍历已知集合或数值区间不支持支持(解构元素)

总结#

  • loop 支持通过 break 值 在跳出时返回计算结果。
  • while let 能极大精简从容器与通道中提取数据时的样板代码。
  • 循环标签('label: loop)提供了清晰、无歧义的多层循环控制能力。

参考资料#