Say I need to model some living things. All living things need to do stuff:
trait LivingThing {
fn do_stuff(&self);
}
I might have sub-traits like animals and plants that do different things. Say I model an animal like this:
trait Animal {
fn do_other_stuff(&self);
fn food(&self) {
println!("Looking for food!");
}
}
impl LivingThing for dyn Animal {
fn do_stuff(&self) {
self.food();
self.do_other_stuff();
}
}
The food
function does not need self
at the moment, but I am just trying to keep things simple here. The do_other_stuff
function exists to ensure sub-traits can add their own functionality which is automatically called when calling the do_stuff
function. Like a human, for example:
struct Human {}
impl Animal for Human {
fn do_other_stuff(&self) {
println!("Taking a shower!");
}
}
I can now do this to automatically have the Human
functionality as well as the Animal
functionality.
let some_human = Human {};
LivingThing::do_stuff(&some_human as &dyn Animal);
// Prints: Looking for food!
// Taking a shower!
What I dislike about this is that I can't do this
let some_human = Human {};
some_human.do_stuff();
because Human
doesn't implement the LivingThing
trait. But I feel like there is no conflict because Human implements Animal
which implements LivingThing
. Sure, Human
could implement 10 different traits that all implement LivingThing
but if there is just one implementation it should be clear what I am trying to do. Do I just have to live with this? Or is there a better way to add to the functionality of do_stuff
in sub-traits?
What I have done until now is invert the model: Have Human
implement LivingThing
and Animal
and have a trait-bound for Animal: LivingThing
. The issue is, that I need to remember to call the Animal
's food
function from the Human
which is not ideal.
CodePudding user response:
Your other option would be to use generics to implement LivingThing
for all types that implement Animal
impl<T> LivingThing for T
where T: Animal {
fn do_stuff(&self) {
self.food();
self.do_other_stuff();
}
}
However, until specialization is stabilized, this approach means directly implementing LivingThing
on any type that implements Animal
(such as Human
) will cause an implementation conflict.