【问题标题】:Why does Rust allow code with the wrong return type, but only with a trailing semicolon?为什么 Rust 允许返回类型错误的代码,但只允许尾随分号?
【发布时间】:2020-06-05 10:10:45
【问题描述】:

考虑以下 Rust 代码:

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

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

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

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)

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


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

【问题讨论】:

  • Rust 编译器需要推断函数体的类型。在第一种情况下,没有返回表达式,显然由于无限循环,编译器将! 推断为返回类型,这是有道理的。在第二种情况下,有一个返回表达式,因此类型推断求解器使用它来推断类型,这也很有意义。我不认为这是在语言参考中指定的,我认为这在任何方面都不重要——只要省略 unreachable 语句就可以了。
  • @SvenMarnach 仍然是关于语言的问题。我认为这仍然是主题。
  • @SvenMarnach 真的有必要吗?我是 Rust 的新手,我试图理解为什么编译器会这样做。我不要求任何哲学答案。我认为您的 cmets 对我的问题有一些误解,并有助于人们认为 SO 是有毒的。
  • @6005 Sven 的 cmets 与 SO 被指控的“有毒文化”完全无关(除非你真的认为他因为你的性别、性取向、种族等而区别对待你)。他为关于您的问题是否适合 SO 的(文明)讨论做出了贡献。
  • 也许我有点简洁,但我当然没有冒犯的意思。我不认为你的问题有什么问题——我什至喜欢它。 :) 我只是不认为有任何“正确”的答案,因为没有指定 Rust 中类型推断的细节。在这种情况下,我们可以看到类型推断 做了什么,但根本没有任何更深层次的原因。也许对编译器内部有深入了解的人可以解释为什么编译器会这样,但我们不会对这种语言了解太多。

标签: rust return-type unreachable-code


【解决方案1】:

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

fn f() -> !

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

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

【讨论】:

  • 链接到 Rust 书中的 section about it 可能会有所帮助。具体来说,它指出:“描述这种行为的正式方式是 ! 类型的表达式可以强制转换为任何其他类型。
  • 谢谢!这很有趣,我会读到这个。但是,警告与此无关:警告只是“无法访问的语句”(指向最后一个println!
  • 这正是我所暗示的。该语句无法访问,您的返回类型为 !。
  • 感谢您的回答,我希望它是正确的,我不接受错误的解释:)
【解决方案2】:

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

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

我认为这在语言参考中没有指定,我认为这在任何方面都无关紧要 - 只需省略 unreachable 语句就可以了。

【讨论】:

    猜你喜欢
    • 2012-07-20
    • 1970-01-01
    • 1970-01-01
    • 2021-05-30
    • 2020-05-26
    • 2021-04-01
    • 2021-12-15
    • 2017-11-03
    相关资源
    最近更新 更多