使用泛型类型时,如何实现“From”的冲突?

我正在尝试实现一个错误枚举,它可能包含与我们的某个特征相关的错误,如下所示:

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>并且MyErrorS::Error我所看到的类型不同。

我是否遗漏了仿制药的基本内容?

使用泛型类型时,如何实现“From”的冲突?

慕侠2389804
浏览 514回答 2
2回答

小唯快跑啊

这里的问题是有人可能会实现,Storage以便From你写的impl与标准库中的impl重叠impl<T> From<T> for T(也就是说,任何东西都可以转换为自身)。特别,struct&nbsp;Tricky;impl&nbsp;Storage&nbsp;for&nbsp;Tricky&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;type&nbsp;Error&nbsp;=&nbsp;MyError<Tricky>;}(这里的设置意味着这实际上不是编译 -&nbsp;MyError<Tricky>无限大 - 但该错误与关于impls / coherence /重叠的推理无关,实际上小的改变MyError可以使其编译而不改变基本问题,例如添加一个Box像StorageProblem(Box<S::Error>),。)如果我们用你的impl&nbsp;Tricky代替S,我们得到:impl&nbsp;From<MyError<Tricky>>&nbsp;for&nbsp;MyError<Tricky>&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;...}这impl与使用T==&nbsp;的自转换完全匹配MyError<Tricky>,因此编译器不知道选择哪一个。Rust编译器避免了这样的情况,而不是进行任意/随机选择,因此必须拒绝原始代码,因为存在这种风险。这种一致性限制肯定会令人烦恼,并且是专业化是一个备受期待的特性的原因之一:本质上允许手动指示编译器如何处理重叠......至少,当前受限形式的扩展之一允许这样做。

繁星淼淼

一致性问题的解决方法是使用Result::map_err自己执行转换。然后,您可以使用末尾Result带有try!或?:fn&nbsp;example<S:&nbsp;Storage>(s:&nbsp;S)&nbsp;->&nbsp;Result<i32,&nbsp;MyError<S>>&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;s.do_a_thing().map_err(MyError::StorageProblem)?; &nbsp;&nbsp;&nbsp;&nbsp;Ok(42)}当存在具有相同底层的错误变体时,此解决方案也很有用Error,例如,如果要分离“文件打开”和“文件读取”错误,两者都是io::Error。
打开App,查看更多内容
随时随地看视频慕课网APP