为什么 Rust 允许具有错误返回类型的代码,但只允许带有尾随分号?

600*_*005 9 return-type unreachable-code rust

考虑以下 Rust 代码:

fn f() -> i32 {
    loop {
        println!("Infinite loop!");
    }
    println!("Unreachable");
}
Run Code Online (Sandbox Code Playgroud)

尽管返回类型是错误的,但它会编译(带有警告)并运行。似乎编译器()对最后一行中的返回类型没有问题,因为它检测到此代码无法访问。

但是,如果我们删除最后一个分号:

fn f() -> i32 {
    loop {
        println!("Infinite loop!");
    }
    println!("Unreachable")
}
Run Code Online (Sandbox Code Playgroud)

然后代码不再编译,给出一个类型错误:

error[E0308]: mismatched types
  --> src/main.rs:14:5
   |
14 |     println!("Unreachable")
   |     ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `()`
   |
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
Run Code Online (Sandbox Code Playgroud)

为什么是这样?()在这两个代码片段中,返回类型不是相同的吗?


注意:我有兴趣了解为什么 Rust 编译器在这两个示例上的行为不同,即 Rust 编译器是如何实现的。从语言设计的角度来看,我并不是要问一个关于它“应该”如何表现的哲学问题(我知道这样的问题可能会偏离主题)。

les*_*how 7

第一个代码块中的返回类型实际上是!(称为 never),因为您有一个永远不会退出的循环(因此 rust 会警告您说它无法访问)。完整的类型是:

fn f() -> !

我怀疑!它更像是 Rust 中的“底部”类型,而不是其他任何东西。在第二种情况下,您的函数可能会在类型检查的早期阶段出错,因为在编译器进行“不可达性”分析之前 i32 和 () 之间不匹配,就像在第一个示例中那样。

编辑:正如建议的那样,这是锈书的相关部分https://doc.rust-lang.org/book/ch19-04-advanced-types.html#the-never-type-that-never-returns

  • 链接到[有关它的部分](https://doc.rust-lang.org/book/ch19-04-advanced-types.html#the-never-type-that-never-returns)可能会有所帮助铁锈书。具体来说,它指出:*“描述此行为的正式方式是,**类型`!`的表达式可以强制转换为任何其他类型。**”* (2认同)