请考虑以下以Rust为单位的自定义错误枚举:
#[derive(Debug)]
pub enum MyError<T: FromStr>
where <T as FromStr>::Err: fmt::Debug
{
Variant1,
Variant2,
FromStrErr(<T as FromStr>::Err),
}
100
一个人可以买impl Display
英镑.因为有了derive
宏,它已经是Debug
了.人们甚至可以按照预期使用它:
fn main() {
fn parse(s: &str) -> Result<u32, MyError<u32>> {
s.parse::<u32>().map_err(MyError::FromStrErr)
}
println!("{:?}", parse("32")); //→ Ok(32)
println!("{:?}", parse("32a")); //→ Err(FromStrErr(ParseIntError { kind: InvalidDigit }))
}
然而,cannot所做的是impl std::error::Error
:
impl<T: FromStr> std::error::Error for MyError<T>
where <T as FromStr>::Err: fmt::Debug
{ }
Even though MyError<T>
is Debug + Display
, this impl
produces the error: T
doesn't implement Debug
.
Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=61f2e7673143b94f142795a7f00f5148
错误消息中的详细信息包括:
-
T
cannot be formatted using{:?}
because it doesn't implementDebug
This is true but ultimately irrelevant becauseT
is not in thestruct
at all. -
note: required for
MyError<T>
to implementDebug
More interesting but blatantly incorrect becauseMyError<T>
already did implementDebug
just fine!
显然,有无数种方法可以解决这个错误,但我想知道的是why这种情况正在发生:为什么在类型上添加一个特征会 destruct 它?
也许是因为From<…> for Box<dyn …>
中几乎不可能发现的impl
,或者它(目前还)不是core
中的,但任何与std::error::Error
有隐约关联的东西总是让我不安地感觉到,幕后有一些特定于这一特征的"魔力",我不明白,当我从目前阻碍我的事情继续前进的时候,我可能会在六个月后发现.然而,有趣的是,在这种情况下情况并非如此--将我自己的标记性状作为实验产生了完全相同的错误:
pub trait MyErrorTrait: fmt::Debug + fmt::Display { }
impl<T: FromStr> MyErrorTrait for MyError<T>
where <T as FromStr>::Err: fmt::Debug
{ }
该代码片段also生成一个错误,声明T
不是Debug
(已确认),并且T
必须是Debug
才能使MyError<T>
实现Debug
--后一部分为假.(playground gist中包含的片段,上面链接,但已注释掉:11.27-31)