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

2023-12-29

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

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> and MyError与以下类型不同S::Error据我所知。

我在这里遗漏了一些关于泛型的基本知识吗?


这里的问题是有人可能会实施Storage所以这样From您编写的 impl 与标准库中的 impl 重叠impl<T> From<T> for T(也就是说,任何东西都可以转化为自身)。

具体来说,

struct Tricky;

impl Storage for Tricky {
    type Error = MyError<Tricky>;
}

(这里的设置意味着这实际上并不能编译——MyError<Tricky>是无限大的——但是这个错误与推理无关impls/连贯性/重叠,以及确实的小变化MyError可以在不改变根本问题的情况下使其编译,例如添加一个Box like StorageProblem(Box<S::Error>),.)

如果我们替代Tricky代替S在你的实现中,我们得到:

impl From<MyError<Tricky>> for MyError<Tricky> {
    ...
}

This impl与自转换完全匹配T == MyError<Tricky>,因此编译器不知道选择哪一个。 Rust 编译器不会做出任意/随机的选择,而是避免了这种情况,因此由于这种风险,原始代码必须被拒绝。

这种连贯性限制肯定会很烦人,也是原因之一专业化 https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md是一个备受期待的功能:本质上允许手动指示编译器如何处理重叠......至少,扩展之一 https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md#the-lattice-rule目前的限制形式允许这样做。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用泛型类型时,“From”的实现如何会发生冲突? 的相关文章

随机推荐