13-循环表达式

循环表达式 — The Rust Reference

译文 · 基于 The Rust Reference

原文链接: https://doc.rust-lang.org/reference/expressions/loop-expr.html

r[expr.loop]

循环表达式

r[expr.loop.syntax]

LoopExpression ->
    LoopLabel? (
        InfiniteLoopExpression
      | PredicateLoopExpression
      | IteratorLoopExpression
      | LabelBlockExpression
    )

r[expr.loop.intro] Rust 支持四种循环表达式:

  • loop 表达式表示无限循环。
  • while 表达式循环直到谓词为假。
  • for 表达式从迭代器中取出值,循环直到迭代器为空。
  • [带标签的块表达式][expr.loop.block-labels]恰好运行一次循环,但允许用 break 提前退出。

r[expr.loop.break-label] 所有四种循环都支持 break 表达式和标签。

r[expr.loop.continue-label] 除带标签的块表达式外,都支持 continue 表达式。

r[expr.loop.explicit-result] 只有 loop 和带标签的块表达式支持求值为非平凡值。

r[expr.loop.infinite]

无限循环

r[expr.loop.infinite.syntax]

InfiniteLoopExpression -> `loop` BlockExpression

r[expr.loop.infinite.intro] loop 表达式会持续重复执行其循环体:loop { println!("I live."); }。

r[expr.loop.infinite.diverging] 没有关联 break 表达式的 loop 表达式是发散的,类型为 !。

r[expr.loop.infinite.break] 含有关联 break 表达式的 loop 表达式可能终止,其类型必须与 break 表达式的值兼容。

r[expr.loop.while]

谓词循环

r[expr.loop.while.syntax]

PredicateLoopExpression -> `while` Conditions BlockExpression

r[expr.loop.while.intro] while 循环表达式允许在一组条件保持为真时重复求值一个块。

r[expr.loop.while.condition] 条件操作数必须是具有布尔类型的[表达式][Expression],或是条件式 let 匹配。若所有条件操作数都求值为 true,且所有 let 模式都成功匹配其被检视表达式,则执行循环体块。

r[expr.loop.while.repeat] 循环体成功执行后,会重新求值条件操作数,以决定是否再次执行循环体。

r[expr.loop.while.exit] 若任一条件操作数求值为 false,或任一 let 模式未能匹配其被检视表达式,则不执行循环体,执行从 while 表达式之后继续。

r[expr.loop.while.eval] while 表达式求值为 ()。

示例:

1
2
3
4
5
6
let mut i = 0;

while i < 10 {
    println!("hello");
    i = i + 1;
}

r[expr.loop.while.let]

while let 模式

r[expr.loop.while.let.intro] while 条件中的 let 模式允许在模式匹配成功时把新变量绑定到作用域中。以下示例演示了使用 let 模式的绑定:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let mut x = vec![1, 2, 3];

while let Some(y) = x.pop() {
    println!("y = {}", y);
}

while let _ = 5 {
    println!("Irrefutable patterns are always true");
    break;
}

r[expr.loop.while.let.desugar] while let 循环等价于如下包含 match 表达式的 loop 表达式。

1
2
3
'label: while let PATS = EXPR {
    /* 循环体 */
}

等价于

1
2
3
4
5
6
'label: loop {
    match EXPR {
        PATS => { /* 循环体 */ },
        _ => break,
    }
}

r[expr.loop.while.let.or-pattern] 可以用 | 运算符指定多个模式。其语义与 match 表达式中的 | 相同:

1
2
3
4
5
let mut vals = vec![2, 3, 1, 2, 2];
while let Some(v @ 1) | Some(v @ 2) = vals.pop() {
    // 打印 2、2,然后是 1
    println!("{}", v);
}

r[expr.loop.while.chains]

while 条件链

r[expr.loop.while.chains.intro] 多个条件操作数可以用 && 分隔。其语义和限制与 if 条件链相同。

以下示例演示了串联多个表达式、混合 let 绑定与布尔表达式,并且后续表达式可以引用先前表达式中的模式绑定:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
fn main() {
    let outer_opt = Some(Some(1i32));

    while let Some(inner_opt) = outer_opt
        && let Some(number) = inner_opt
        && number == 1
    {
        println!("Peek a boo");
        break;
    }
}

r[expr.loop.for]

迭代器循环

r[expr.loop.for.syntax]

IteratorLoopExpression ->
    `for` Pattern `in` Expression _except [StructExpression]_ BlockExpression

r[expr.loop.for.intro] for 表达式是一种语法构造,用于遍历由 std::iter::IntoIterator 的实现所提供的元素。

r[expr.loop.for.condition] 若迭代器产生一个值,则将该值与不可反驳模式匹配,执行循环体,然后将控制返回到 for 循环的头部。若迭代器为空,则 for 表达式完成。

遍历数组内容的 for 循环示例:

1
2
3
4
5
let v = &["apples", "cake", "coffee"];

for text in v {
    println!("I like {}.", text);
}

遍历一系列整数的 for 循环示例:

1
2
3
4
5
let mut sum = 0;
for n in 1..11 {
    sum += n;
}
assert_eq!(sum, 55);

r[expr.loop.for.desugar] for 循环等价于如下包含 match 表达式的 loop 表达式:

1
2
3
'label: for PATTERN in iter_expr {
    /* 循环体 */
}

等价于

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
    let result = match IntoIterator::into_iter(iter_expr) {
        mut iter => 'label: loop {
            let mut next;
            match Iterator::next(&mut iter) {
                Option::Some(val) => next = val,
                Option::None => break,
            };
            let PATTERN = next;
            let () = { /* 循环体 */ };
        },
    };
    result
}

r[expr.loop.for.lang-items] 此处的 IntoIterator、Iterator 和 Option 始终是标准库中的项,而不是当前作用域中这些名字所解析到的任何其它项。

变量名 next、iter 和 val 仅用于说明,用户并不能键入这些实际名字。

注意 外层的 match 用于确保 iter_expr 中的任何临时值在循环结束前不会被丢弃。next 在赋值前先声明,是为了更经常地正确推断类型。

r[expr.loop.label]

循环标签

r[expr.loop.label.syntax]

LoopLabel -> LIFETIME_OR_LABEL `:`

r[expr.loop.label.intro] 循环表达式可以可选地带有一个_标签_。标签写成循环表达式之前的生命周期,例如 'foo: loop { break 'foo; }、'bar: while false {}、'humbug: for _ in 0..0 {}。

r[expr.loop.label.control-flow] 若存在标签,则嵌套在该循环内的带标签 break 和 continue 表达式可以退出该循环,或将控制返回到其头部。见 break 表达式和 continue 表达式。

r[expr.loop.label.ref] 标签遵循与局部变量相同的卫生性和遮蔽规则。例如,下面的代码会打印 “outer loop”:

1
2
3
4
5
6
7
'a: loop {
    'a: loop {
        break 'a;
    }
    print!("outer loop");
    break 'a;
}

'_ 不是合法的循环标签。

r[expr.loop.break]

break 表达式

r[expr.loop.break.syntax]

BreakExpression -> `break` LIFETIME_OR_LABEL? Expression?

r[expr.loop.break.intro] 遇到 break 时,立即终止所关联循环体的执行,例如:

1
2
3
4
5
6
7
8
let mut last = 0;
for x in 1..100 {
    if x > 12 {
        break;
    }
    last = x;
}
assert_eq!(last, 12);

r[expr.loop.break.diverging] break 表达式是发散的,类型为 !。

r[expr.loop.break.label] break 表达式通常关联到包围它的最内层 loop、for 或 while 循环,但可以使用标签指定受影响的外围循环。示例:

1
2
3
4
5
'outer: loop {
    while true {
        break 'outer;
    }
}

r[expr.loop.break.value] break 表达式只允许出现在循环体中,形式为 break、break 'label,或(见下文)break EXPR 或 break 'label EXPR。

r[expr.loop.break-value.implicit-value] 在[带 break 表达式的 loop][expr.loop.break-value]或带标签的块表达式中,不带表达式的 break 等价于 break ()。

r[expr.loop.block-labels]

带标签的块表达式

r[expr.loop.block-labels.syntax]

LabelBlockExpression -> BlockExpression

r[expr.loop.block-labels.intro] 带标签的块表达式与块表达式完全相同,只是允许在块内使用 break 表达式。

r[expr.loop.block-labels.break] 与循环不同,带标签块表达式内的 break 表达式必须带有标签(即标签不是可选的)。

r[expr.loop.block-labels.label-required] 同样,带标签的块表达式必须以标签开头。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
## fn do_thing() {}
## fn condition_not_met() -> bool { true }
## fn do_next_thing() {}
## fn do_last_thing() {}
let result = 'block: {
    do_thing();
    if condition_not_met() {
        break 'block 1;
    }
    do_next_thing();
    if condition_not_met() {
        break 'block 2;
    }
    do_last_thing();
    3
};

r[expr.loop.block-labels.type] 带标签块表达式的类型是所有 break 操作数与最终操作数的最小上界。若省略最终操作数,则最终操作数的类型默认为单元类型;除非该块[发散][expr.block.diverging],此时为 never 类型。

r[expr.loop.continue]

continue 表达式

r[expr.loop.continue.syntax]

ContinueExpression -> `continue` LIFETIME_OR_LABEL?

r[expr.loop.continue.intro] 遇到 continue 时,立即终止所关联循环体的当前迭代,将控制返回到循环头部。

r[expr.loop.continue.diverging] continue 表达式是发散的,类型为 !。

r[expr.loop.continue.while] 对于 while 循环,头部是控制该循环的条件操作数。

r[expr.loop.continue.for] 对于 for 循环,头部是控制该循环的调用表达式。

r[expr.loop.continue.label] 与 break 一样,continue 通常关联到最内层外围循环,但可以使用 continue 'label 指定受影响的循环。

r[expr.loop.continue.in-loop-only] continue 表达式只允许出现在循环体中。

r[expr.loop.break-value]

break 与循环值

r[expr.loop.break-value.intro] 当与 loop 关联时,break 表达式可以通过 break EXPR 或 break 'label EXPR 的形式从该循环返回一个值,其中 EXPR 是一个表达式,其结果从该 loop 返回。例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
let (mut a, mut b) = (1, 1);
let result = loop {
    if b > 10 {
        break b;
    }
    let c = a + b;
    a = b;
    b = c;
};
// Fibonacci 数列中第一个大于 10 的数:
assert_eq!(result, 13);

r[expr.loop.break-value.type] 带关联 break 表达式的 loop 的类型是所有 break 操作数的最小上界。

r[expr.loop.break-value.diverging] 带关联 break 表达式的 loop 在任一 break 操作数不发散时不会发散。若所有 break 操作数都发散,则该 loop 表达式也发散。

最后修改 August 21, 2026: 更新 (76fc81a2e)