问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/51966865/how-do-i-make-many-different-structs-that-all-implement-the-same-trait-comparabl