我正在尝试实现一个错误枚举,它可能包含与我们的某个特征相关的错误,如下所示:
trait Storage {
type Error;
}
enum MyError<S: Storage> {
StorageProblem(S::Error),
}
Run Code Online (Sandbox Code Playgroud)
我还试图实现From特性以允许MyError从一个实例构建Storage::Error:
impl<S: Storage> From<S::Error> for MyError<S> {
fn from(error: S::Error) -> MyError<S> {
MyError::StorageProblem(error)
}
}
Run Code Online (Sandbox Code Playgroud)
(游乐场)
但是这无法编译:
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;
Run Code Online (Sandbox Code Playgroud)
我不明白为什么编译器认为这已经实现了.错误消息告诉我已经有一个From<MyError<_>>(有)的实现,但我不是试图在这里实现 - 我正在尝试实现,From<S::Error>并且MyError与S::Error我能看到的类型不同.
我是否遗漏了仿制药的基本内容?
huo*_*uon 10
这里的问题是有人可能会实现,Storage以便From你写的impl与标准库中的impl重叠impl<T> From<T> for T(也就是说,任何东西都可以转换为自身).
特别,
struct Tricky;
impl Storage for Tricky {
type Error = MyError<Tricky>;
}
Run Code Online (Sandbox Code Playgroud)
(这里的设置意味着这实际上不是编译 - MyError<Tricky>无限大 - 但该错误与关于impls/coherence /重叠的推理无关,实际上小的改变MyError可以使其编译而不改变基本问题,例如添加一个Box像StorageProblem(Box<S::Error>),.)
如果我们用你的impl Tricky代替S,我们得到:
impl From<MyError<Tricky>> for MyError<Tricky> {
...
}
Run Code Online (Sandbox Code Playgroud)
这impl与使用T== 的自转换完全匹配MyError<Tricky>,因此编译器不知道选择哪一个.Rust编译器避免了这样的情况,而不是进行任意/随机选择,因此必须拒绝原始代码,因为存在这种风险.
这种一致性限制肯定会令人讨厌,并且是专业化是一个备受期待的特性的原因之一:本质上允许手动指示编译器如何处理重叠...至少,当前受限形式的扩展之一允许这样做.
解决一致性问题的一种方法是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)
}
Run Code Online (Sandbox Code Playgroud)
当存在具有相同基础的错误变体时Error,例如,如果您要分隔“文件打开”和“文件读取”错误,两者都为,则该解决方案也很有价值io::Error。
| 归档时间: |
|
| 查看次数: |
1558 次 |
| 最近记录: |