I'm trying to make a vector
that would store objects of different structs that implement a certain trait
, however, I really want my trait to be a supertrait of Eq
(and thus PartialEq
).
The Book provides a way to do that with Vec<Box<dyn Draw>>
, however, the PartialEq
dependency seems to disallow this approach with the trait cannot be made into an object error.
This answer provides a way to do a similar thing for HashMap
s. However, this approach seems too verbose for what I am trying to achieve.
What would be the idiomatic way to have a vector for structs implementing such a trait?
Code to reproduce below and on the playground
pub trait MyTrait: PartialEq { fn my_func() -> bool; }
pub struct Struct1 { age: i32 }
impl PartialEq<Self> for Struct1 {
fn eq(&self, other: &Self) -> bool { self.age == other.age }
}
impl MyTrait for Struct1 {
fn my_func() -> bool { false }
}
pub struct Struct2 { year: i32 }
impl PartialEq<Self> for Struct2 {
fn eq(&self, other: &Self) -> bool { self.year == other.year }
}
impl MyTrait for Struct2 {
fn my_func() -> bool { true }
}
fn main() {
let mut v: Vec<Box<dyn MyTrait>> = Vec::new();
// v.push(Struct1 { age: 1 });
// v.push(Struct2 { year: 2 });
}
CodePudding user response:
Depending on your actual use case, this may or may not work for you, but from the info in your question and comment, I wouldn't go the trait object route but rather the enum route. Have all the types you want to store as variants on an enum, for example like this:
pub trait MyTrait: PartialEq { fn my_func(&self) -> bool; }
pub enum Struct {
Struct1 {
age: i32,
},
Struct2 {
year: i32,
}
}
impl PartialEq<Self> for Struct {
fn eq(&self, other: &Self) -> bool {
use Struct::*;
match (self, other) {
(Struct1 { age: age1 }, Struct1 { age: age2 }) => age1 == age2,
(Struct2 { year: year1 }, Struct2 { year: year2 }) => year1 == year2,
_ => false
}
}
}
impl MyTrait for Struct {
fn my_func(&self) -> bool {
use Struct::*;
match self {
Struct1 { .. } => false,
Struct2 { .. } => true,
}
}
}
fn main() {
let mut v: Vec<Struct> = Vec::new();
v.push(Struct::Struct1 { age: 1 });
v.push(Struct::Struct2 { year: 2 });
assert!(v.contains(&Struct::Struct2 { year: 2 }));
}
Feel free to let me know if there are more constraints that would make this approach infeasible.