为什么我会因为缺少类型注释而收到错误“不满足 trait bound FromStr”?

Sor*_*tad 5 types traits pattern-matching rust

我遇到了一个编译错误,它似乎突出显示了我对类型系统不了解的内容。

我想将字符串转换为整数,如果字符串不是有效整数,则会显示自定义恐慌消息。我做matchResult是通过真实返回parse()

fn main() {
    let x = match "23".parse() {
        Ok(int) => int,
        Err(_) => panic!("Not an integer!"),
    };
    println!("x plus 1 is {}", x+1);
}
Run Code Online (Sandbox Code Playgroud)

(如果这真的是我在我的程序中所做的一切,我只会使用expect(),但在实际程序中还有更多。)

我希望24在编译和运行时输出。相反,会出现以下编译器错误:

fn main() {
    let x = match "23".parse() {
        Ok(int) => int,
        Err(_) => panic!("Not an integer!"),
    };
    println!("x plus 1 is {}", x+1);
}
Run Code Online (Sandbox Code Playgroud)

问题似乎是 Rust 不知道我要解析为什么类型,这可能是一个问题是有道理的。如果我将第 2 行更改为以下内容,错误就会消失:

    let x: i32 = match "23".parse() {
Run Code Online (Sandbox Code Playgroud)

为什么我收到错误消息,而不是指示需要类型注释的消息?该消息似乎在抱怨错误臂不返回任何内容(或者更准确地说,它返回的内容——即什么都没有——没有实现该FromStr特征),但在调用之后对我来说没有任何意义panic!,匹配的那个分支的输出类型可能会产生任何影响——程序可能会展开堆栈并在那时立即终止,因此类型安全似乎无关紧要!

一个提示是,如果panic!我不调用,而是简单地返回一个整数(例如,Err(_) => 0),则代码编译良好(并按预期工作)。在这种情况下,Rust 似乎正确地将类型推断为i32第一次,并且不会运行任何导致混淆错误的代码路径。

kfe*_*v91 5

该消息似乎在抱怨错误臂不返回任何内容(或者更准确地说,它返回的内容——即什么都没有——没有实现该FromStr特征)。

其实你第一次就对了。错误臂永远不会返回。的返回类型panic!字面上称为从不类型( !) 并且它与确实返回的单元类型( ())不同,尽管它返回的是“无”。

专业提示:永远不会返回的函数称为发散函数。

对我来说,在调用 之后panic!,匹配的那个分支的输出类型可能会产生任何影响,这对我来说没有任何意义。

它没有。never 类型对类型推断没有影响,可以代替任何其他类型使用。例如,此程序编译时没有任何错误或警告:

#![allow(unreachable_code)]

fn main() {
    let _x: () = panic!();
    let _y: i32 = panic!();
    let _z: &dyn ToString = panic!();
}
Run Code Online (Sandbox Code Playgroud)

然而,我们使用上面的一堆类型注释来操作返回类型,而不是任何类型提示,Rust 似乎解决了默认的()for 表达式,!如您的示例的这个简化版本所示:

#![allow(unreachable_code)]

fn main() {
    let x = panic!();
    x + 5;
}
Run Code Online (Sandbox Code Playgroud)

哪个抛出:

error[E0277]: cannot add `i32` to `()`
  --> src/main.rs:15:7
   |
15 |     x + 5;
   |       ^ no implementation for `() + i32`
   |
   = help: the trait `std::ops::Add<i32>` is not implemented for `()`
Run Code Online (Sandbox Code Playgroud)

鉴于空表达式(例如空块)的计算结果为单元类型,这似乎是一个合理的选择。

简而言之:当您将一个发散函数作为表达式中的最终语句并且不使用任何类型注释时,Rust 会推断该表达式的返回类型为(). 这就是推断您的错误臂返回的()原因以及您收到FromStr not implemented for ()错误的原因。