循环和其他可中断的表达式

语法
循环表达式 :
   循环标签? (
         无限循环表达式
      | 断言循环表达式
      | 断言模式循环表达式
      | 迭代循环表达式
      | 标签块表达式
   )

Rust 支持五种循环表达式:

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

无限循环

语法
无限循环表达式 :
   loop 块表达式

loop 表达式不断重复执行其主体: loop { println!("I live."); }

没有相关的 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 表达式

标签遵循局部变量的卫生和隐藏规则。例如,以下代码将打印 "outer loop" :

#![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 表达式通常与包含它的最内层 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 和循环值

在 Rust 中,当与 loop 关键字相关联时,可以使用 break 表达式通过 break EXPRbreak 'label EXPR 的形式从循环中返回一个值,其中 EXPR 是返回给 loop 的表达式结果。 例如:

#![allow(unused)]
fn main() {
let (mut a, mut b) = (1, 1); // 初始化 a 和 b 为 1
let result = loop { // 进入循环
    if b > 10 { // 如果 b 大于 10
        break b; // 跳出循环并返回 b 的值
    }
    let c = a + b; 
    a = b; // 将 a 赋值为上一个 b 的值
    b = c; // 将 b 赋值为上一个 c 的值
};
// 斐波那契数列中第一个大于 10 的数是 13 :
assert_eq!(result, 13);
}

loop 语句中,如果有关联的 break 语句,则不被视为发散,而且 loop 语句必须与每个 break 表达式兼容的类型。 未表明表达式的 break 语句的表达式被视为 ()