【问题标题】:Why does "break" not need a semicolon when ending a "loop"?为什么在结束“循环”时“中断”不需要分号?
【发布时间】:2021-03-09 11:27:31
【问题描述】:

摘自 Rust Book 的Chapter 3.5

我们使用带有值counter * 2break 关键字。在循环之后,我们使用分号结束将值分配给result 的语句。

加上代码sn-p:

fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

        if counter == 10 {
            break counter * 2;
        }
    };

    println!("The result is {}", result);
}

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

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

【问题讨论】:

标签: loops rust syntax break keyword


【解决方案1】:

一个更短的例子:

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

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

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

如果分号被去掉,break 被评估为the never type !,这将强制转换为任何其他类型。这意味着它将满足外部范围所期望的任何类型。所以一切都很好,只要您不尝试在 if 块结束之前附加任何其他语句。

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

另见:

【讨论】:

    【解决方案2】:

    The Rust Language Reference on Expression Statements:

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

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

    我想这纯粹是为了美学和人体工程学,因为几乎所有东西都是 Rust 的表达方式。如果结尾的分号在所有表达式之后都是强制性的,那么我们必须用看起来很糟糕的分号来终止 if-else 块(也是表达式):

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

    同样,我们可以省略所有控制流表达式的结尾分号,因为它们产生控制流,因此分号的典型功能,即丢弃表达式的结果并取而代之为(),变得无关紧要。

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

    在上面的例子中,如果我们用分号终止return 5并没有什么不同,因为无论如何都不能“捕获”该表达式的结果,因为它会产生控制流。对于breakcontinue 等其他控制流表达式也是如此。

    【讨论】:

    • 很好的解释。不过,让我把这个做对——如果我们从“return 5”中删除“return”,分号将成为强制性的,对吧?否则程序将无法编译。
    • @PaulRazvanBerg 实际上相反。如果没有关键字 return,将隐式返回 5,而分号将禁止该返回,而是返回 (),这将与函数签名不兼容。
    • 该死,这就是我的意思。必须删除分号。感谢@IvanC 的更正。
    猜你喜欢
    • 1970-01-01
    • 2014-03-15
    • 2017-01-27
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 2017-03-20
    • 1970-01-01
    相关资源
    最近更新 更多