我正在尝试实现一个错误枚举,它可能包含与我们的某个特征相关的错误,如下所示:trait Storage {
type Error;}enum MyError<S: Storage> {
StorageProblem(S::Error),}我还试图实现From特性以允许MyError从一个实例构建Storage::Error:impl<S: Storage> From<S::Error> for MyError<S> {
fn from(error: S::Error) -> MyError<S> {
MyError::StorageProblem(error)
}}但是这无法编译:error[E0119]: conflicting implementations of trait `std::convert::From<MyError<_>>` for type `MyError<_>`:
--> src/lib.rs:9:1
|
9 | impl<S: Storage> From<S::Error> for MyError<S> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<T> std::convert::From<T> for T;我不明白为什么编译器认为这已经实现了。错误消息告诉我已经有一个From<MyError<_>>(有)的实现,但我不想在这里实现 - 我正在尝试实现,From<S::Error>并且MyError与S::Error我所看到的类型不同。我是否遗漏了仿制药的基本内容?使用泛型类型时,如何实现“From”的冲突?
2 回答
小唯快跑啊
TA贡献1863条经验 获得超2个赞
这里的问题是有人可能会实现,Storage
以便From
你写的impl与标准库中的impl重叠impl<T> From<T> for T
(也就是说,任何东西都可以转换为自身)。
特别,
struct Tricky;impl Storage for Tricky { type Error = MyError<Tricky>;}
(这里的设置意味着这实际上不是编译 - MyError<Tricky>
无限大 - 但该错误与关于impl
s / coherence /重叠的推理无关,实际上小的改变MyError
可以使其编译而不改变基本问题,例如添加一个Box
像StorageProblem(Box<S::Error>),
。)
如果我们用你的impl Tricky
代替S
,我们得到:
impl From<MyError<Tricky>> for MyError<Tricky> { ...}
这impl
与使用T
== 的自转换完全匹配MyError<Tricky>
,因此编译器不知道选择哪一个。Rust编译器避免了这样的情况,而不是进行任意/随机选择,因此必须拒绝原始代码,因为存在这种风险。
这种一致性限制肯定会令人烦恼,并且是专业化是一个备受期待的特性的原因之一:本质上允许手动指示编译器如何处理重叠......至少,当前受限形式的扩展之一允许这样做。
繁星淼淼
TA贡献1775条经验 获得超11个赞
一致性问题的解决方法是使用Result::map_err
自己执行转换。然后,您可以使用末尾Result
带有try!
或?
:
fn example<S: Storage>(s: S) -> Result<i32, MyError<S>> { s.do_a_thing().map_err(MyError::StorageProblem)?; Ok(42)}
当存在具有相同底层的错误变体时,此解决方案也很有用Error
,例如,如果要分离“文件打开”和“文件读取”错误,两者都是io::Error
。
添加回答
举报
0/150
提交
取消