【问题标题】:Conflicting trait implementations even though associated types differ即使关联类型不同,特征实现也存在冲突
【发布时间】:2016-11-03 01:42:02
【问题描述】:

我正在尝试创建一个包含isizeAtomicIsize 的通用结构,但是当我尝试为结构的两种可能实现实现特征时遇到错误。我创建了一个最小的示例,在下面演示了我的问题。

use std::sync::atomic::{AtomicIsize, Ordering};
use std::ops::Deref;
use std::marker::PhantomData;

pub trait Counted {
    fn inc(&self, value: isize);
}

pub type PlainCounter = isize;
pub type AtomicCounter = AtomicIsize;


pub struct Counter<'a, T: 'a> {
    counter: T,
    phantom: PhantomData<&'a T>,
}

impl<'a, T> Counter<'a, T>
    where T: Deref<Target = PlainCounter>
{
    pub fn new(counter: T) -> Self {
        Counter {
            counter: counter,
            phantom: PhantomData,
        }
    }
}

impl<'a, T> Counted for Counter<'a, T>
    where T: Deref<Target = PlainCounter>
{
    fn inc(&self, value: isize) {
        self.counter += 1;
    }
}

impl<'a, T> Counter<'a, T>
    where T: Deref<Target = AtomicCounter>
{
    pub fn new(counter: T) -> Self {
        Counter {
            counter: counter,
            phantom: PhantomData,
        }
    }
}

impl<'a, T> Counted for Counter<'a, T>
    where T: Deref<Target = AtomicCounter>
{
    fn inc(&self, value: isize) {
        self.counter.fetch_add(value, Ordering::SeqCst);
    }
}

(playground)

我得到的错误是编译器找到了conflicting implementations of trait `Counted` for type `Counter&lt;'_, _&gt;`。似乎编译器无法确定实现是针对两种不同类型的T,即T: Deref&lt;Target = PlainCounter&gt;T: Deref&lt;Target = AtomicCounter&gt;。有没有办法向编译器提供额外的信息,以便它可以区分这两种情况,还是我完全走错了路?

【问题讨论】:

  • 我认为您会遇到问题,因为您有两个 impls 看起来它们可以重叠,即使关联的类型阻止它实际发生。我可能会尝试为您的两种具体类型实现 {a, the} 特征,然后为 Counter&lt;T&gt; where T: Counted 和委托实现它。
  • @Shepmaster:我认为这是一个答案?
  • 我很想看看你的意思的例子@Shepmaster - 我想我明白你的意思,但一个例子会很棒。
  • @Shepmaster 我采纳了您的建议并为PlainCounterAtomicCounter 实施了Counted,然后实施了Counter&lt;T&gt; where T: Counted,其中Counter 上的调用只是委托给它的counter 字段和一切都很好。我对这个例子做了一些小的调整,让它更符合这个新方法,如果你有兴趣,例子是here

标签: generics struct types rust


【解决方案1】:

您可以通过定义执行实际工作的第二个特征来完成此模式,并为(Counter&lt;'a, T&gt;, &lt;T as Deref&gt;::Target) 实现,并让Counter 特征调用该实现。

我认为这不是很清楚,但我认为一个例子可以很好地说明。为了清楚起见,使用 Shepmaster 的较短示例,我们将从以下内容出发:

use std::ops::Deref;

trait Foo {}

impl<T> Foo for T
    where T: Deref<Target = u8>
{}

impl<T> Foo for T
    where T: Deref<Target = bool>
{}

fn main() {}

到这里:

use std::ops::Deref;

trait Foo {}
trait InnerFoo {}

impl<T> Foo for T
    where T: Deref,
          (T, <T as Deref>::Target): InnerFoo
{}

impl<T> InnerFoo for (T, u8)
{}

impl<T> InnerFoo for (T, bool)
{}

fn main() {}

【讨论】:

  • 我发现有点不清楚——我们如何在内部 trait 中实际实现引用 self 的函数?看起来self 会是例如(T, u8),但大概因为我们正在实施Deref&lt;Target=u8&gt;,我们实际上并没有具体的u8
  • 想通了:给InnerFoo一个类型变量&lt;T&gt;,那么特征函数的第一个参数可以是t: T。将 &lt;T&gt; 添加到 Foo 的 (T, …) : InnerFoo 约束。然后拨打&lt;(T, &lt;T as Deref&gt;::Target) as InnerFoo&lt;T&gt;&gt;::my_fn(self, …)。最后,InnerFoo 的实现需要额外的约束where T : Deref&lt;Target=…&gt;。然后你可以在那个impl中调用t.deref()
  • 你也可以这样删除元组类型中的第一个T
  • 对于像AsRef 这样的特征会是什么样子?
  • AsRef 没有关联类型,因此此模式不适用。
【解决方案2】:

不幸的是,这还没有在语言中实现。

有这个跟踪问题:rust-lang/rust#20400

还提出了一个 RFC rust-lang/rfcs#1672 来解决这个问题,但随后被推迟到 Chalk integration,这将使其更易于实施。

与此同时,您必须使用建议的解决方法above

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-31
    • 1970-01-01
    • 1970-01-01
    • 2019-12-08
    • 1970-01-01
    相关资源
    最近更新 更多