Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

oop - How do I make many different structs that all implement the same trait comparable to each other?

In Java-lingo, I have an interface R, an interface RT extends R (where RT implements all of R) and a bunch of other classes that all implement RT.

Transitioning to Rust I ended up with two traits

trait R { ... }
trait RT { ... }

where RT is a "subtrait" of R:

impl R for X where X: RT { ... }

Following that I have a bunch of structs, all of which implement RT:

struct RV { ... }
impl RT for RV { ... }

struct I { ... }
impl RT for I { ... }

struct U { ... }
impl RT for U { ... }

// ...

So far so good.

Now I want all of these structs to be comparable to each other, on the basis that all of them implement RT.

In Java I would change RT to

interface RT extends R, Comparable<RT>

and add a default implementation for equals and compareTo.

In Rust I have no idea if or how this could be approached.

I could say trait RT: PartialEq, but that would only make one implementation comparable with itself (RV == RV, but not RV == U).

My next idea was to add blanket implementations for every struct:

impl PartialEq<RV> for X where X: RT
impl PartialEq<I> for X where X: RT
// ...

I understand why this isn't allowed, however I'm still stuck with my initial problem.

I can't cast the values for comparison (RV as RT == U as RT) because RT can't be made into an object.

I could manually implement PartialEq<T> for every combination of structs but that would be a lot of duplication.

I considered using a macro to generate all the different implementations, but that feels so much like brute-forcing, that I question the initial design of my program.

How do I make all the different structs comparable to each other?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

That pattern often arises in Java to emulate tagged unions, which are missing from the Java language. In Rust, unless you are writing a library whose users may need to define new implementations of RT, I suspect you’ll be happier with an enum instead of a trait object:

#[derive(PartialEq, Eq)]
enum AnyRT {
    RV(RV),
    I(I),
    U(U),
}

impl RT for AnyRT {
    fn foo(&self, ...) {
        match self {
            AnyRT::RV(rv) => rv.foo(...),
            AnyRT::I(i) => i.foo(...),
            AnyRT::U(u) => u.foo(...),
        }
    }
}

Depending on your application, you may then find that you don’t need the RT trait and/or the separate RV, I, U structs at all.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...