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

Why does Rust allow code with the wrong return type, but only with a trailing semicolon?

考虑以下 Rust 代码:

fn f() -> i32 {
    loop {
        println!("Infinite loop!");
    }
    println!("Unreachable");
}

尽管 return 类型是错误的,但它编译(带有警告)并运行。 编译器似乎可以接受最后一行 () 的 return 类型,因为它检测到此代码无法访问。

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

fn f() -> i32 {
    loop {
        println!("Infinite loop!");
    }
    println!("Unreachable")
}

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

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)

这是为什么?在这两个代码片段中,return 类型是否相同 ()


注意: 我很想了解为什么 Rust 编译器在这两个示例中的行为不同,即 Rust 编译器是如何实现的。我并不是要从语言设计的角度问一个关于它 "should" 行为方式的哲学问题(我知道这样的问题可能会跑题)。

第一个代码块中的 return 类型实际上是 ! (调用 never),因为你有一个永不退出的循环(所以 rust 给你一个警告,说它无法访问)。完整类型为:

fn f() -> !

我怀疑 ! 更像是 Rust 中的 'bottom' 类型。在第二种情况下,您的函数可能会在类型检查的早期阶段出错,因为在编译器进入 'unreachability' 分析之前 i32 和 () 之间不匹配,就像第一个示例中那样。

编辑:按照提示,这里是rust book的相关部分https://doc.rust-lang.org/book/ch19-04-advanced-types.html#the-never-type-that-never-returns

(将斯文的第一条评论转化为答案)

Rust 编译器需要推断函数体的类型。在第一种情况下,没有 return 表达式,显然编译器推断 !作为 return 类型,因为无限循环,这是有道理的。在第二种情况下,有一个 return 表达式,因此类型推断求解器使用它来推断类型,这也是有道理的。

我不认为这在语言参考中指定,也不认为它有任何关系 - 只需省略无法访问的语句就可以了。