如何将Rust Result<T, E>的错误转换为Result<T, Box<dyn std::error::Error>>?

3
我正在尝试将由reqwest::blocking::get函数返回的Result泛型化。它返回一个Result<reqwest::blocking::Response, reqwest::Error>,但调用该函数的函数则返回一个Result<reqwest::blocking::Response, Box<dyn std::error::Error>

  • 我的第一次尝试为什么无法编译通过?
  • 最惯用的方法是什么以进行此转换?

这是第一次尝试:

fn get_example_fails() -> Result<Response, Box<dyn Error>> {
        let result = blocking::get("http://example.com");
        result.map_err(|error| Box::new(error))
    }

以下是我不知道如何修复的错误,但我感觉通过一些微调可能会更加习惯用语 - 但我不确定需要微调什么:

error[E0308]: mismatched types
   --> src/bittrex.rs:143:9
    |
141 |     fn get_example_fails() -> Result<Response, Box<dyn Error>> {
    |                               -------------------------------- expected `Result<reqwes
t::blocking::Response, Box<(dyn StdError + 'static)>>` because of return type
142 |         let result = blocking::get("http://example.com");
143 |         result.map_err(|error| Box::new(error))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn StdError`, 
found struct `reqwest::Error`
    |
    = note: expected enum `Result<_, Box<(dyn StdError + 'static)>>`
               found enum `Result<_, Box<reqwest::Error>>`

这个尝试编译通过了,但似乎有些啰嗦:

fn get_example_works() -> Result<Response, Box<dyn Error>> {
        let result = blocking::get("http://example.com");
        match result {
            Ok(resp) => Ok(resp),
            Err(error) => Err(Box::new(error)),
        }
    }
1个回答

5
这是因为编译器过于严格了。请注意,Box::new(error)只是将error放入一个Box中,因此您得到了一个强类型的Box<reqwest:Error>,就像编译器报告的一样。但是你想要的是dyn Error的trait对象,而Box<reqwest:Error>可以是它,但编译器没有做出这种类型减弱的假设。修复方法是手动明确这一点:
fn get_example_fails() -> Result<Response, Box<dyn Error>> {
        let result = blocking::get("http://example.com");
        result.map_err(|error| Box::new(error) as Box<dyn Error>)
}

注意额外的as Box<dyn Error>, 这使编译器清楚地知道应该将值向下转换,并消除了它是在Box中的具体reqwest::Error的事实。
第二个例子能够编译通过的原因在于类型推导。在第一个例子中,从函数返回的类型将是从.map_err()返回的类型,这是一个Result<Response, Box<reqwest::Error>> - 就是这样。类型不匹配,所以会出错。在第二个例子中,match构建了一个全新的Result,Rust必须为此推断TE;因此类型推导发挥作用。在这种情况下,由于函数的返回值,关于Box<dyn Error>的推断是成功的。但是在map_err()中,类型推导无法“深入”到map_err()的主体并削弱其返回类型;太晚了,类型已经固定了。这就是为什么要按照上面建议的手动处理。

但是你想要的是一个dyn Error的特质对象,而Box<reqwest:Error>可以是。我不同意。你可以从Box<reqwest:Error>创建一个Box<dyn Error>,但是一个Box<reqwest:Error>不能成为(或者“被用作”,等等)一个Box<dyn Error>(例如,因为Box<reqwest:Error>内部只包含一个指针,而Box<dyn Error>包含两个)。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接