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

时间:2018-06-28 08:32:10

标签: rust pattern-matching

我有一个匹配表达式,希望从中返回错误。似乎编译器无法推断出最后一种情况eErr(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();
}

错误是:

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>, _>`

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

3 个答案:

答案 0 :(得分:8)

因为Err不是类型。

ErrResult<T, E>的变体,其类型为Result<T, E>。由于Result<T, E>Result<U, E>之外与T == U不同,并且由于没有隐式转换,因此您需要显式执行转换。

我承认它看起来确实很愚蠢,因为类型推断会推论得出TUE,但在语义上这2个Err(e) => return Err(e)的级别不同。

再举一个愚蠢的例子:

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, } } Term<'a>的类型不同,除非Term<'static>。当'a == 'static主要包含非生命周期参数时,它会变得很乏味:(

答案 1 :(得分:3)

如果您对Err(e) => return Err(e)案例使用合格的类型,事情将会更加清楚。您在这里真正说的是:

Result<Option<u8>, String>::Err(e) => return Result<u8, String>::Err(e)

这样编写后,很明显正在进行转换。相反,e => return e等效于:

Result<Option<u8>, String>::Err(e) => return Result<Option<u8>, String>::Err(e)

类型错误,因为您的函数应该返回Result<u8, String>

答案 2 :(得分:2)

您要匹配Result<Option<u8>, String>,因此e属于这种类型,但是您的函数要求返回值必须是Result<u8, String>的类型:

note: expected type `std::result::Result<u8, _>`
         found type `std::result::Result<std::option::Option<u8>, _>`