使用泛型类型时,“From"的实现如何存在冲突? [英] How is there a conflicting implementation of `From` when using a generic type?
问题描述
我正在尝试实现一个错误枚举,它可以包含与我们的特征之一相关的错误,如下所示:
I'm trying to implement an error enum which can contain an error associated with one of our traits like this:
trait Storage {
type Error;
}
enum MyError<S: Storage> {
StorageProblem(S::Error),
}
我还尝试实现 From
trait 以允许从 Storage::Error
的实例构建 MyError
:>
I have also tried to implement the From
trait to allow construction of MyError
from an instance of a 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
和 MyError
与我所看到的 S::Error
的类型不同.
I don't understand why the compiler reckons this has already been implemented. The error message is telling me that there's already an implementation of From<MyError<_>>
(which there is), but I'm not trying to implement that here - I'm trying to implement From<S::Error>
and MyError
is not the same type as S::Error
from what I can see.
我在这里是否遗漏了泛型的一些基础知识?
Am I missing something fundamental to generics here?
推荐答案
这里的问题是有人可能会实现 Storage
以便您编写的 From
实现与impl
(即任何东西都可以转换为自身).
The problem here is someone may implement Storage
so that the From
impl you have written overlaps with the impl in the standard library of impl<T> From<T> for T
(that is, anything can be converted to itself).
具体来说,
struct Tricky;
impl Storage for Tricky {
type Error = MyError<Tricky>;
}
(这里的设置意味着这实际上并不编译—MyError
impl
的推理无关/coherence/overlap,实际上对 MyError
的小改动可以让它在不改变基本问题的情况下编译,例如添加一个 Box
像 StorageProblem(Box<S::错误>),
.)
(The set-up here means this doesn't actually compile—MyError<Tricky>
is infinitely large—but that error is unrelated to the reasoning about impl
s/coherence/overlap, and indeed small changes to MyError
can make it compile without changing the fundamental problem, e.g. adding a Box
like StorageProblem(Box<S::Error>),
.)
如果我们在你的实现中用 Tricky
代替 S
,我们得到:
If we substitute Tricky
in place of S
in your impl, we get:
impl From<MyError<Tricky>> for MyError<Tricky> {
...
}
这个 impl
与 T
== MyError
完全匹配自转换,因此编译器不会知道选择哪一个.Rust 编译器不会做出任意/随机的选择,而是避免了这种情况,因此由于这种风险,必须拒绝原始代码.
This impl
exactly matches the self-conversion one with T
== MyError<Tricky>
, and hence the compiler wouldn't know which one to choose. Instead of making an arbitrary/random choice, the Rust compiler avoids situations like this, and thus the original code must be rejected due to this risk.
这种连贯性限制肯定很烦人,这也是 专业化 是一个备受期待的功能:本质上允许手动指示编译器如何处理重叠......至少,其中一个扩展允许这样做.
This coherence restriction can definitely be annoying, and is one of reasons that specialisation is a much-anticipated feature: essentially allows manually instructing the compiler how to handle overlap... at least, one of the extensions to the current restricted form allows that.
这篇关于使用泛型类型时,“From"的实现如何存在冲突?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!