为什么"break"在结束"loop"时不需要分号?



《铁锈之书》第3.5章节选:

我们使用值为counter * 2break关键字。在循环之后,我们使用分号结束为result赋值的语句。

加上代码片段:

fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!("The result is {}", result);
}

我理解这是如何工作的,以及为什么结果是20,但我注意到,如果我删除包含break关键字的行上的分号,该程序是等效的。

为什么在这种情况下分号是可选的?

一个简短的例子:

let _: i32 = loop {
if true {
break 3; // ()
}
};

这只是分号不干扰预期结果的另一个例子。首先,分号的插入引入了一个表达式语句,其计算结果为单元类型()。由于loops和if表达式继续允许评估为相同类型()的代码块,因此所有类型都是一致的。

let _: i32 = loop {
if true {
break 3 // ! coerced to ()
}
};

如果去掉分号,则break被求值为never类型!,它强制为任何其他类型。这意味着它将满足外部范围所期望的任何类型。在这种情况下,单独的break 3也变为()以实现if表达式。所以一切都很好,只要你不试图在if块的末尾之前附加任何其他语句。

breakreturn都评估为!,因为它们的副作用意味着该程序将不会按照自然工作流程进行。

另请参阅:

  • 为什么返回表达式在';你没有必要吗
  • 什么';在Rust中使用return语句和省略分号有什么区别
  • 如何静态断言函数的末尾不可达

表达式语句上的Rust语言引用:

表达式语句是计算表达式并忽略其结果的语句。通常,表达式语句的目的是触发对其表达式求值的效果。

仅由块表达式或控制流表达式组成的表达式,如果在允许语句的上下文中使用,则可以省略尾部分号

我想这纯粹是为了美学和人体工程学,因为几乎所有的东西都是Rust中的一种表达。如果所有表达式后面的分号都是强制性的,那么我们就必须终止If-elses用分号阻塞(也是表达式(,这看起来很糟糕:

if {
// do something
} else {
// do something else
}; // <- gross

类似地,我们可以省略所有控制流表达式上的尾随分号,因为它们产生控制流,因此分号的典型功能,即丢弃表达式的结果并计算为(),变得无关紧要。

fn five() -> i32 {
return 5 // to semicolon or not to semicolon? it doesn't matter
}

在上面的例子中,如果我们用分号或不用分号终止CCD_;捕获";该表达式的结果,因为它生成控制流。对于其他控制流表达式,如CCD_ 18和CCD_。

最新更新