循环和其他可中断表达式

语法

循环表达式 :

   循环标签? (

         无限循环表达式

      | 谓词循环表达式

      | 谓词模式循环表达式

      | 迭代器循环表达式

      | 带标签的块表达式

   )

Rust 支持五种循环表达式

所有五种类型的循环都支持 break 表达式标签。除带标签的块表达式外,所有表达式都支持 continue 表达式。只有 loop 和带标签的块表达式支持 对非平凡值的求值

无限循环

语法

无限循环表达式 :

   loop 块表达式

loop 表达式连续重复执行其主体:loop { println!("我还活着。"); }

没有关联 break 表达式的 loop 表达式是发散的,其类型为 !。包含关联 break 表达式loop 表达式可能会终止,并且必须具有与 break 表达式的值兼容的类型。

谓词循环

语法

谓词循环表达式 :

   while 表达式结构体表达式除外 块表达式

while 循环首先计算 布尔循环条件操作数。如果循环条件操作数计算结果为 true,则循环体块执行,然后控制权返回到循环条件操作数。如果循环条件表达式计算结果为 false,则 while 表达式完成。

一个例子

#![allow(unused)]
fn main() {
let mut i = 0;

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

谓词模式循环

语法

谓词模式循环表达式 :

   while let 模式 = 被匹配值惰性布尔运算符表达式除外 块表达式

while let 循环在语义上类似于 while 循环,但在条件表达式的位置,它需要关键字 let,后跟一个模式、一个 =、一个 被匹配值表达式和一个块表达式。如果被匹配值的值与模式匹配,则循环体块执行,然后控制权返回到模式匹配语句。否则,while 表达式完成。

#![allow(unused)]
fn main() {
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;
}
}

while let 循环等效于包含 match 表达式loop 表达式,如下所示。

'label: while let PATS = EXPR {
    /* loop body */
}

等效于

'label: loop {
    match EXPR {
        PATS => { /* loop body */ },
        _ => break,
    }
}

可以使用 | 运算符指定多个模式。这与 match 表达式中的 | 具有相同的语义

#![allow(unused)]
fn main() {
let mut vals = vec![2, 3, 1, 2, 2];
while let Some(v @ 1) | Some(v @ 2) = vals.pop() {
    // Prints 2, 2, then 1
    println!("{}", v);
}
}

if let 表达式的情况一样,被匹配值不能是 惰性布尔运算符表达式

迭代器循环

语法

迭代器循环表达式 :

   for 模式 in 表达式结构体表达式除外 代码块表达式

for 表达式是一种语法结构,用于循环遍历由 std::iter::IntoIterator 的实现提供的元素。如果迭代器产生一个值,则该值将与不可反驳的模式进行匹配,执行循环体,然后控制权返回到 for 循环的头部。如果迭代器为空,则 for 表达式完成。

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

#![allow(unused)]
fn main() {
let v = &["apples", "cake", "coffee"];

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

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

#![allow(unused)]
fn main() {
let mut sum = 0;
for n in 1..11 {
    sum += n;
}
assert_eq!(sum, 55);
}

for 循环等效于包含 match 表达式loop 表达式,如下所示

'label: for PATTERN in iter_expr {
    /* loop body */
}

等效于

{
    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 () = { /* loop body */ };
        },
    };
    result
}

IntoIteratorIteratorOption 在这里始终是标准库项,而不是这些名称在当前作用域中解析成的任何内容。变量名 nextiterval 仅用于说明,它们实际上没有用户可以键入的名称。

注意:使用外部 match 是为了确保在循环完成之前不会丢弃 iter_expr 中的任何 临时值next 在赋值之前声明,因为它会导致更频繁地正确推断类型。

循环标签

语法

循环标签 :

   生命周期或标签 :

循环表达式可以选择有一个标签。标签写成循环表达式前面的生命周期,如 'foo: loop { break 'foo; }'bar: while false {}'humbug: for _ in 0..0 {}。如果存在标签,则嵌套在此循环中的带标签的 breakcontinue 表达式可以退出此循环或将控制权返回到其头部。请参阅 break 表达式continue 表达式

标签遵循局部变量的卫生和遮蔽规则。例如,此代码将打印“外部循环”

#![allow(unused)]
fn main() {
'a: loop {
    'a: loop {
        break 'a;
    }
    print!("outer loop");
    break 'a;
}
}

break 表达式

语法

Break 表达式 :

   break 生命周期或标签? 表达式?

遇到 break 时,将立即终止关联循环体的执行,例如

#![allow(unused)]
fn main() {
let mut last = 0;
for x in 1..100 {
    if x > 12 {
        break;
    }
    last = x;
}
assert_eq!(last, 12);
}

break 表达式通常与包含 break 表达式的最内层 loopforwhile 循环相关联,但可以使用 标签 来指定受影响的封闭循环。示例

#![allow(unused)]
fn main() {
'outer: loop {
    while true {
        break 'outer;
    }
}
}

break 表达式只允许在循环体中使用,并且具有 breakbreak 'label 或(见下文break EXPRbreak 'label EXPR 中的一种形式。

带标签的代码块表达式

语法

带标签的代码块表达式 :

   代码块表达式

带标签的代码块表达式与代码块表达式完全相同,只是它们允许在代码块中使用 break 表达式。与循环不同,带标签的代码块表达式中的 break 表达式必须具有标签(即标签不是可选的)。类似地,带标签的代码块表达式必须以标签开头。

#![allow(unused)]
fn main() {
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
};
}

continue 表达式

语法

Continue 表达式 :

   continue 生命周期或标签?

遇到 continue 时,将立即终止关联循环体的当前迭代,并将控制权返回到循环头部。在 while 循环的情况下,头部是控制循环的条件表达式。在 for 循环的情况下,头部是控制循环的调用表达式。

break 一样,continue 通常与最内层的封闭循环相关联,但可以使用 continue 'label 来指定受影响的循环。continue 表达式只允许在循环体中使用。

break 和循环值

当与 loop 关联时,可以使用 break 表达式从该循环返回一个值,方法是使用 break EXPRbreak 'label EXPR 形式之一,其中 EXPR 是一个表达式,其结果从 loop 返回。例如

#![allow(unused)]
fn main() {
let (mut a, mut b) = (1, 1);
let result = loop {
    if b > 10 {
        break b;
    }
    let c = a + b;
    a = b;
    b = c;
};
// first number in Fibonacci sequence over 10:
assert_eq!(result, 13);
}

如果 loop 有一个关联的 break,则它不被认为是发散的,并且 loop 必须具有与每个 break 表达式兼容的类型。没有表达式的 break 被认为与表达式为 ()break 相同。