使用rustc 1.30.1和reqwest 0.9.5。
我有一个函数可以调用其他几个函数,这些函数可能会返回不同类型的错误,尤其是std::io::Error
和reqwest::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
生命周期来自何处。如果事实证明这无关紧要,我可能会对此提出另一个问题。
答案 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
。