Reputation: 13
My enum has 40ish variants with about half of them implementing the trait, but here is a simpler example:
trait CheeseBoard {
fn say_cheese(self);
}
struct Cheese {
name: String,
}
impl CheeseBoard for Cheese {
fn say_cheese(self) {
println!("I am {}", self.name);
}
}
struct Person {
name: String,
}
impl CheeseBoard for Person {
fn say_cheese(self) {
println!("{} says cheese!", self.name);
}
}
enum CheesyPerson {
Cheese(Cheese),
Person(Person),
UncheesyNonperson,
}
fn main() {
let _a = [
CheesyPerson::Cheese(Cheese {
name: "Gouda".into(),
}),
CheesyPerson::Person(Person {
name: "Peer".into(),
}),
CheesyPerson::UncheesyNonperson,
];
todo!("Call say_cheese on items in _a where the enum variant has exactly one field that implements the CheeseBoard trait.")
}
Upvotes: 0
Views: 1567
Reputation: 359
Thank @cdhowie, your comment saves me from another hours of torment!
In case anyone wraps the enum with another layer of struct, ensure that you borrow the enum, not copy it. For example,
struct RoomForOne(CheesyPerson);
impl RoomForOne {
fn get_cheese_board(&self) -> Option<&dyn CheeseBoard> {
match &self.0 { // & here is important!
CheesyPerson::Cheese(v) => Some(v),
CheesyPerson::Person(v) => Some(v),
_ => None,
}
}
}
Upvotes: 0
Reputation: 169008
This isn't directly possible in Rust; it has no mechanism to even match on "any enum possibility that has a single value," let alone that implements a particular trait.
The cleanest way I can think of to implement this is with a helper method that gives back a Option<&dyn CheeseBoard>
:
impl CheesyPerson {
fn get_cheese_board(&self) -> Option<&dyn CheeseBoard> {
match self {
Self::Cheese(v) => Some(v),
Self::Person(v) => Some(v),
_ => None,
}
}
}
Now you can do something like this:
for v in _a.iter().filter_map(|v| v.get_cheese_board()) {
v.say_cheese();
}
Note this requires changing your CheeseBoard::say_cheese
method because right now it takes self
by value, consuming the CheeseBoard
in the process. The method needs to take self
by reference.
trait CheeseBoard {
fn say_cheese(&self);
// ^
// Add this to take self by reference
}
Upvotes: 1