为什么不匹配map_err调用就编译普通匹配表达式?

时间:2018-12-01 12:01:59

标签: rust

使用rustc 1.30.1和reqwest 0.9.5。

我有一个函数可以调用其他几个函数,这些函数可能会返回不同类型的错误,尤其是std::io::Errorreqwest::Error

要将它们传播给调用者,最简单的解决方案似乎是将它们放在Box中,该变量可以方便地实现From<Error>特性和Error特性本身。像这样:

fn fetch_input() -> Result<String, Box<dyn Error>> {
    ...
    let session_cookie = load_session_cookie()?; // Returns Result<String, io::Error>
    let text: Result<String, reqwest::Error> = ...;
    text.map_err(Box::new) // Compile error on this line
}

但是,该代码无法编译:

error[E0308]: mismatched types                                                               
  --> src/main.rs:26:5                                                                       
   |                                                                                         
16 | fn fetch_input() -> Result<String, Box<dyn Error>> {                 
   |                     ------------------------------ expected `std::result::Result<std::string::String, std::boxed::Box<(dyn std::error::Error + 'static)>>` because of return type
...                                                                                          
26 |     text.map_err(Box::new)                                                              
   |     ^^^^^^^^^^^^^^^^^^^^^^ expected trait std::error::Error, found struct `reqwest::Error`
   |                                                                                         
   = note: expected type `std::result::Result<_, std::boxed::Box<(dyn std::error::Error + 'static)>>`
              found type `std::result::Result<_, std::boxed::Box<reqwest::Error>>`           

如果我用一个简单的旧map_err表达式替换match调用,一切都很好:

    match text {
        Ok(t) => Ok(t),
        Err(e) => Err(Box::new(e)),
    }

请注意,这与标准库中map_err实现的主体相同。那么,为什么我的map_err呼叫没有通过类型检查器?不用说,reqwest::Error does implement the std::error::Error trait

我还想知道错误消息中的'static生命周期来自何处。如果事实证明这无关紧要,我可能会对此提出另一个问题。

1 个答案:

答案 0 :(得分:3)

{Box::new做一件事,而只能做一件事:取一个reqwest::Error并将其放在Box<reqwest::Error>内。

表达式 Box::new(e)在做两件事:调用Box::new,它将reqwest::Error放入{{ 1}},然后然后Box<reqwest::Error>强制转换为Box<reqwest::Error>

强制类型是Rust通常试图避免的。 Box<dyn Error>Box<T>(以及其他类似的直接指针→指针强制)是一个例外。特别是,Rust 不会Box<dyn Trait>强制转换为Result<T, Box<Err>>

就您而言:因为Result<T, Box<dyn Error>>始终需要关联的生存期。当您将dyn Trait放在一个盒子中时,它被隐式假定为dyn Trait。当您拥有'static时,它被假定为&'a dyn Trait