为什么我会因为缺少类型注释而收到错误 "trait bound FromStr is not satisfied"?

Why do I get the error "trait bound FromStr is not satisfied" because of a missing type annotation?

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

我想将字符串转换为整数,如果字符串不是有效整数,则使用自定义紧急消息。我在由 parse():

编辑的 return 上做了一个 match
fn main() {
    let x = match "23".parse() {
        Ok(int) => int,
        Err(_) => panic!("Not an integer!"),
    };
    println!("x plus 1 is {}", x+1);
}

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

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

error[E0277]: the trait bound `(): std::str::FromStr` is not satisfied
 --> main.rs:2:24
  |
2 |     let x = match "23".parse() {
  |                        ^^^^^ the trait `std::str::FromStr` is not implemented for `()`

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

    let x: i32 = match "23".parse() {

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

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

The message appears to be complaining that the error arm does not return anything (or more precisely, that what it returns -- namely nothing -- doesn't implement the FromStr trait).

其实你第一次是对的。错误臂永远不会 returns。 panic! 的 return 类型字面上称为 never type (!) and it's different from the unit type (()),它执行 return,尽管它 return 是“无” .

专业提示:从不 return 的函数称为发散函数。

it doesn't make any sense to me that, after calling panic!, the type of the output of that arm of the match could have any effect whatsoever.

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

#![allow(unreachable_code)]

fn main() {
    let _x: () = panic!();
    let _y: i32 = panic!();
    let _z: &dyn ToString = panic!();
}

然而,我们正在使用上面的一堆类型注释来操作 return 类型,以代替任何类型提示,无论 Rust 似乎对表达式的默认设置 () return ! 如示例的简化版本所示:

#![allow(unreachable_code)]

fn main() {
    let x = panic!();
    x + 5;
}

抛出:

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 `()`

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

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