rust - 为什么普通匹配表达式可以编译,而 map_err 调用却不能?
问题描述
使用 rustc 1.30.1 和 reqwest 0.9.5。
我有一个调用其他几个函数的函数,这些函数可能会返回不同类型的错误,尤其是std::io::Error
和reqwest::Error
.
要将这些传播给调用者,最简单的解决方案似乎是将它们放在 a 中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
确实实现了std::error::Error
trait。
我也想知道'static
错误消息中的生命周期是从哪里来的。如果它被证明是无关的,我可能会为它打开一个不同的问题。
解决方案
Box::new
做一件事,而且只做一件事:接受 areqwest::Error
并将其放入 aBox<reqwest::Error>
中。
该表达式 Box::new(e)
正在做两件事:调用Box::new
将 areqwest::Error
放入 aBox<reqwest::Error>
中,然后强制将Box<reqwest::Error>
a 放入 aBox<dyn Error>
中。
强制类型是 Rust 通常试图避免的。 Box<T>
→ Box<dyn Trait>
(和其他类似的,直接指针→指针强制)是一个例外。特别是,Rust不会强制Result<T, Box<Err>>
.Result<T, Box<dyn Error>>
至于你的旁白:因为dyn Trait
总是需要一个相关的生命周期。当您放入dyn Trait
一个盒子时,它被隐含地假定为'static
。当你有&'a dyn Trait
时,它被假定为'a
。
推荐阅读
- javascript - HTML中的无效数字输入
- java - 如何解决 iText (java) 中的这个编译错误?
- url - Zendesk 文章编号无故更改
- python - 如何以可读性和有效的方式创建一个可迭代组合的字典,并将它们的索引元组作为键?
- python - 使用 selenium python 查找元素锚类元素导致 css 选择器错误
- python - 多重继承中的超级
- ios - 将 UITableView 上的选择限制为 2
- git - 将分叉存储库与分叉子模块同步,将原始存储库与原始子模块同步
- r - Quadprog 用于带约束的投资组合优化
- scala - 使用 sbt 获取存储库内容