为什么在更改结果类型时匹配结果需要显式Err?

lje*_*drz 2 pattern-matching rust

我有一个匹配表达式,我希望可能会从中返回错误.似乎编译器无法推断最后一个案例e是一个Err(String)并且要求模式是显式的:

fn foo() -> Result<Option<u8>, String> {
    unimplemented!() // don't mind the panic here
}

fn foo2() -> Result<u8, String> {
    let bar = foo();

    for _ in 0..3 {
        let baz = match bar {
            Ok(Some(b)) => b,
            Ok(None)    => continue,
            Err(e)      => return Err(e) // works
//          e           => return e      // error[E0308]
        };
    }

    Ok(0)
}

fn main() {
    let _ = foo2();
}
Run Code Online (Sandbox Code Playgroud)

错误是:

error[E0308]: mismatched types
  --> src/main.rs:13:33
   |
13 |           e           => return e      // error[E0308]
   |                                 ^ expected u8, found enum `std::option::Option`
   |
   = note: expected type `std::result::Result<u8, _>`
              found type `std::result::Result<std::option::Option<u8>, _>`
Run Code Online (Sandbox Code Playgroud)

我很确定我已经用尽了所有的Ok(_)变种,所以唯一留下的应该是Err(_).例如,如果foo()返回Result<u8, String>,则不会发生此错误.我错过了什么吗?

Mat*_* M. 8

因为Err不是一种类型.

ErrResult<T, E>其类型的变体Result<T, E>.由于Result<T, E>是从不同的Result<U, E>,除非T == U,并且由于没有隐式转换,你需要明确地执行转换.

我承认它看起来愚蠢的,因为类型推断负责推断的T,U以及E在这种情况下产生Err(e) => return Err(e)的,但在语义级别的2 Err(e)有不同的类型.

另一个愚蠢的例子:

enum Term<'a> {
    Int(i64),
    String(&'a str),
}

fn staticify(t: Term) -> Term<'static> {
    use Term::*;

    match t {
        String(_) => String("Hello, World!"),
        _ => t,
    }
}
Run Code Online (Sandbox Code Playgroud)

将失败出于同样的原因,因为Term<'a>Term<'static>是不是同一类型,除非'a == 'static.当Term包含大多数非寿命参数时,它变得乏味:(