为所有实现特质的类型实现一个特质

3

我有这个问题:

  • 多个结构体实现了一个trait Event
  • 所有的结构体都可以用相同的方式实现PartialEq trait

我考虑写成这样(简短版)

type Data = Vec<u8>;

trait Event {
    fn data(&self) -> &Data;
}

struct NoteOn {
    data: Data,
}
struct NoteOff {
    data: Data,
}
impl Event for NoteOn {
    fn data(&self) -> &Data {
        &self.data
    }
}
impl Event for NoteOff {
    fn data(&self) -> &Data {
        &self.data
    }
}
impl<T: Event> PartialEq for T {
    fn eq(&self, b: &T) -> bool {
        self.data() == b.data()
    }
}

fn main() {
    println!("Hello, world!");
}

Playground

这段代码编译失败:

error[E0119]: conflicting implementations of trait `std::cmp::PartialEq<&_>` for type `&_`:
  --> src/main.rs:23:1
   |
23 | impl<T: Event> PartialEq for T {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: conflicting implementation in crate `core`:
           - impl<A, B> std::cmp::PartialEq<&B> for &A
             where A: std::cmp::PartialEq<B>, A: ?Sized, B: ?Sized;
   = note: downstream crates may implement trait `Event` for type `&_`

error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
  --> src/main.rs:23:1
   |
23 | impl<T: Event> PartialEq for T {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
   |
   = note: only traits defined in the current crate can be implemented for a type parameter

这里有什么问题吗? 或者是否有另一种实现通用的方式可以避免为 NoteOn 和 Noteff 都重复输入 PartialEq? 谢谢。

看起来您的问题可能已经得到了答案,可以参考这个答案:我为另一个 trait 实现了一个 trait,但无法从两个 trait 中调用方法。如果还有不同之处,请 [编辑] 您的问题以解释清楚。否则,我们可以将此问题标记为已回答。 - Shepmaster
也许您可以解释一下您不理解编译器帮助信息的部分? - Shepmaster
目前,这是如何为我不拥有的类型实现我不拥有的特质?的重复(答案:你不能,但有解决方法)。更广泛地说,我认为您的问题可以通过以下两种方式之一或两种方式同时解决:如何使许多不同的结构体都实现相同的特质并相互比较?如何测试特质对象之间的相等性?(请务必阅读所有答案)。 - trent
你可能想使用enum代替trait,或者为trait对象类型实现PartialEq - trent
Event 不相关;你没有拥有 PartialEqT(对于某个假设的 T),因此你不能为 T 实现 PartialEq - trent
显示剩余5条评论
1个回答

1
这是我尝试以最佳方式实现我想要的功能的“尝试”,但是按照@trentcl和@Shepmaster的建议,我用了不同的方式。如@trentctl所提到的,我使用了Enum来在不同类型之间切换,我将枚举值保留在常见的Event结构中,因此我可以轻松包装不同的对象并添加更多代码到Event中。这样做也有助于创建简单的Vec类型。
在这里,我想象只需要Enum,而不是Event和具有枚举的属性,我还在学习变体枚举的用法。
我也遇到了@trentcl提到的问题,即我没有拥有Vec类型,因此我将Vec包装在一个名为Sec的结构体中,而不是简单地为类型命名别名。这使得我的PartialEq实现与Vec类型分离(如果我理解正确,但我不确定)=>我困扰的原因是我认为使用type A = B;会创建一个新类型,但文档确实说明它是别名(这可能是为什么我无法为Vec实现PartialEq的原因),虽然最终我想象中我可能也很错误,因为我创建了一个人工结构只是为了包装1个属性,这似乎也是低效的。

=> 总之,现在感谢大家,我会继续努力,看看如何使其更加高效,但我想我只是在Rust的上下文中使用了错误的东西,我不确定这是否是一个好答案,并且希望得到反馈或其他建议

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d67b7d993fa6b6285962ee58e9b215e5

type Data = Vec<u8>;

#[derive(Debug)]
enum EventImpl{
    NoteOn(u8),
    NoteOff(u8)
}
#[derive(Debug)]
struct Event{
    data:Data,
    i:EventImpl
}

impl Event{
    fn new(data:Data)->Self{
        Event{
            i: match data[0]{
                0 => EventImpl::NoteOn(data[1]),
                1 => EventImpl::NoteOff(data[1]),
                _ => panic!("unk")
            },
            data:data
        }
    }

    fn data(&self)->&Data{
        &self.data
    }
}
#[derive(Debug)]
struct Seq{
    pub things:Vec<Event>
}

impl PartialEq for Seq{
    fn eq(&self,o:&Self)->bool{
    // i have to learn the iterator implementation    
        let mut r=o.things.len()==self.things.len();
        if ! r{
            return false;
        }
        for i in 0..o.things.len() {
            r = r && o.things[i]==self.things[i];
        }
        r
    }
}
impl PartialEq for Event{
    fn eq(&self,o:&Self)->bool{
    // i have to learn the iterator implementation    
        std::mem::discriminant(&self.i) == std::mem::discriminant(&o.i) && o.data()==self.data()
    }
}


fn main() {
    let mut s:Seq=Seq{things:vec![Event::new(vec![1,2,3])]};
    s.things.push(Event::new(vec![0,1,2]));
    let s2:Seq=Seq{things:vec![Event::new(vec![1,2,3]),Event::new(vec![0,1,2])]};

    println!("Hello, world! {:?} {:?}",s, s.things[1].data());
    println!("S1 == S2 ? {}",s==s2);
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接