这里是一个错误结构体:
#[derive(Debug)]
pub struct Error {
msg: &'static str,
//source: Option<Box<dyn std::error::Error>>, // old
source: Option<Box<dyn std::error::Error + Send>>, // new
}
impl Error {
fn new_caused<E>(msg: &'static str, err: E) -> Self
where
E: 'static + std::error::Error + Send,
{
Self {
msg: msg,
source: Some(Box::from(err)),
}
}
}
impl std::fmt::Display for Error {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "{}", self.msg) // HACK
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.source.as_ref().map(|err| err.as_ref())
}
}
fn main() {
let err = "this will fail".parse::<i32>().unwrap_err();
let err = Error::new_caused("some msg", err);
}
我决定让它可以发送(Send
),所以我将 source: Option<Box<dyn std::error::Error>>
更改为 source: Option<Box<dyn std::error::Error + Send>>
,然后奇怪的事情发生了。
神奇之处 #1
new_caused
拒绝继续编译:
error[E0277]: the trait bound `std::boxed::Box<dyn std::error::Error + std::marker::Send>: std::convert::From<E>` is not satisfied
--> src/main.rs:14:26
|
14 | source: Some(Box::from(err)),
| ^^^^^^^^^^^^^^ the trait `std::convert::From<E>` is not implemented for `std::boxed::Box<dyn std::error::Error + std::marker::Send>`
|
= note: required by `std::convert::From::from`
将Box::from
更改为Box::new
有所帮助,即使它们的签名看起来相同,Box::from
的实现只是调用了Box::new
。
神奇的 #2
source
也变得不正确:
error[E0308]: mismatched types
--> src/main.rs:27:9
|
27 | self.source.as_ref().map(|err| err.as_ref())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait `std::error::Error`, found trait `std::error::Error + std::marker::Send`
|
= note: expected enum `std::option::Option<&(dyn std::error::Error + 'static)>`
found enum `std::option::Option<&dyn std::error::Error + std::marker::Send>`
为什么未使用的
Send
特性不像其他特性一样被忽略?用手动版本替换该组合逻辑运作正常:
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self.source {
Some(source) => Some(source.as_ref()),
None => None
}
}
总结
这种“魔法”的解释是什么,有哪些更好的处理方法?