Why does Rust allow code with the wrong return type, but only with a trailing semicolon?
考虑以下 Rust 代码:
1 2 3 4 5 6
| fn f() -> i32 {
loop {
println!("Infinite loop!");
}
println!("Unreachable");
} |
尽管返回类型错误,它仍会编译(带有警告)并运行。
看起来编译器在最后一行返回类型为 () 是可以的,因为它检测到此代码不可访问。
但是,如果我们删除最后一个分号:
1 2 3 4 5 6
| fn f() -> i32 {
loop {
println!("Infinite loop!");
}
println!("Unreachable")
} |
然后代码不再编译,出现类型错误:
1 2 3 4 5 6 7
| 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) |
这是为什么?这两个代码片段中的返回类型是否相同,()?
注意:我有兴趣了解为什么 Rust 编译器在这两个示例中的行为不同,即 Rust 编译器是如何实现的。从语言设计的angular来看,我并不是要问一个关于它"应该"如何表现的哲学问题(我知道这样的问题可能是题外话)。
- Rust 编译器需要推断函数体的类型。在第一种情况下,没有返回表达式,显然编译器将 ! 推断为返回类型,因为无限循环,这是有道理的。在第二种情况下,有一个返回表达式,因此类型推断求解器使用它来推断类型,这也很有意义。我不认为这是在语言参考中指定的,我也不认为它有任何影响——只要省略 unreachable 语句就可以了。
-
@SvenMarnach 这仍然是关于语言的问题。我认为这仍然是主题。
-
@SvenMarnach 真的有必要吗?我是 Rust 的新手,我试图理解为什么编译器会这样做。我不要求任何哲学答案。我认为您的评论显示了对我的问题的一些误解,并有助于人们认为 SO 是有毒的。
-
@6005 Sven 的评论与 SO 被指控的"有毒文化"完全无关(除非你真的认为他因为你的性别、性取向、种族等而对你有所不同)。他为关于您的问题是否适合 SO 的(文明)讨论做出了贡献。
-
也许我有点简洁,但我当然没有冒犯的意思。我不认为你的问题有什么问题——我什至喜欢它。 :) 我只是不认为有任何"正确"的答案,因为没有指定 Rust 中类型推断的细节。我们可以看到在这种情况下类型推断做了什么,但根本没有任何更深层次的原因。也许对编译器内部有深入了解的人可以解释为什么编译器会这样,但我们不会对这种语言了解太多。
-
@SvenMarnach 感谢您的澄清。只是我要问的是为什么编译器会这样做,仅此而已:) 所以你的第一条评论完全回答了这个问题。我并不是在寻找一些理由来解释为什么 Rust 会这样做(如果不存在的话)。实际上,如果您将评论变成答案,我认为这将是一个很好的答案
-
显然我对你问题的"为什么"部分读了太多。我的评论只是描述了编译器做了什么,但没有说明原因。
-
请注意,您可以通过编写 return <something>; 然后在函数末尾使用自动返回来获得类似的行为。看起来编译器以一种允许它同时查看并将其注册为错误的方式检查事物,即使它无法访问。
第一个代码块中的返回类型实际上是 !(称为 never),因为您有一个永远不会退出的循环(所以 rust 会警告您说它无法访问)。完整的类型是:
fn f() -> !
我怀疑 ! 更像是 Rust 中的"底部"类型,而不是其他任何东西。在第二种情况下,由于 i32 和 () 在编译器进行"不可达性"分析之前不匹配,您的函数可能会在类型检查的早期阶段出错,就像在第一个示例中一样。
编辑:按照建议,这里是 rust 书的相关部分 https://doc.rust-lang.org/book/ch19-04-advanced-types.html#the-never-type-that-never -返回
- 链接到 Rust 书中关于它的部分可能会有所帮助。具体来说,它指出:"描述这种行为的正式方式是 ! 类型的表达式可以强制转换为任何其他类型。"
-
谢谢!这很有趣,我会读到这个。但是,警告与此无关:警告只是"无法访问的语句"(指向最后一个 println!)
-
这正是我所暗示的。该语句无法访问,并且您的返回类型是 !。
-
感谢您的回答,我希望它是正确的,我不接受错误的解释:)
(将 Sven 的第一条评论转化为答案)
Rust 编译器需要推断函数体的类型。在第一种情况下,没有返回表达式,显然编译器推断 !作为返回类型,因为无限循环,这是有道理的。在第二种情况下,有一个返回表达式,因此类型推断求解器使用它来推断类型,这也很有意义。
我不认为这是在语言参考中指定的,我认为这在任何方面都不重要 - 只需省略 unreachable 语句就可以了。