Sorry for the long post.
This question has probably been asked, and replied, many times before, but I'm not finding a similar situation.
It's about polymorphic collections like Vec<Box<dyn Trait>>
.
Let's say I have several recipes defined by the trait Recipe {}
and various fruits defined by the trait Fruit {}
. For each recipe, I want to prepare each fruit appropriately. My approach was to define a trait Ingredient
like this:
trait Ingredient<T>
where
T: Fruit,
{
fn prepare(&self, t: &T);
}
And then, for each recipe and fruit combination, I implemented the Ingredient
trait. For example:
impl Ingredient<Apple> for Bavarian {
fn prepare(&self, b: &Apple) {
println!("Preparing an Apple for Bavarian Fruit Salad -> {self:?} with an {b:?}.");
}
}
This code works as expected:
let apple = Apple {};
let banana = Banana {};
let bavarian = Bavarian {};
bavarian.prepare(&apple); // OK
bavarian.prepare(&banana); // OK
What's confusing me is that the following code doesn't compile:
let poly: Vec<Box<dyn Fruit>> = vec![
Box::new(Apple {}),
Box::new(Banana {})];
for s in poly {
// Next line doesn't compile
bavarian.prepare(&s);
}
I understand that the issue is related to the fact that Box<dyn Fruit>
does not implement the Fruit
trait.
However, if Fruit
defines a method, say eat(&self)
, then the following code compiles and runs fine:
for s in poly {
s.eat(); // OK
}
Here is a (somewhat) minimal example:
use std::fmt::Debug;
// --------------------
trait Fruit: Debug {
fn eat(&self);
}
// --------------------
trait Recipe: Debug {}
// --------------------
trait Ingredient<T>
where
T: Fruit,
{
fn prepare(&self, t: &T);
}
// --------------------
#[derive(Debug)]
struct Apple {}
impl Fruit for Apple {
fn eat(&self) {
println!("Eating an Apple!");
}
}
// --------------------
#[derive(Debug)]
struct Banana {}
impl Fruit for Banana {
fn eat(&self) {
println!("Eating a Banana!");
}
}
// --------------------
#[derive(Debug)]
struct Bavarian {}
impl Recipe for Bavarian {}
impl Ingredient<Apple> for Bavarian {
fn prepare(&self, b: &Apple) {
println!("Preparing an Apple for Bavarian Fruit Salad -> {self:?} with an {b:?}.");
}
}
impl Ingredient<Banana> for Bavarian {
fn prepare(&self, b: &Banana) {
println!("Preparing a Banana for Bavarian Fruit Salad -> {self:?} with a {b:?}.");
}
}
// --------------------
fn main() {
let apple = Apple {};
let banana = Banana {};
let bavarian = Bavarian {};
bavarian.prepare(&apple); // OK
bavarian.prepare(&banana); // OK
let poly: Vec<Box<dyn Fruit>> = vec![Box::new(Apple {}), Box::new(Banana {})];
for s in poly {
s.eat(); // OK
bavarian.prepare(&s); // Error
// the trait bound `Bavarian: Ingredient<Box<dyn Fruit>>` is not satisfied
// the trait `Ingredient<Box<dyn Fruit>>` is not implemented for `Bavarian`
}
}