Reputation: 45
I have the following in my tests which compiles and works well:
#[test]
fn zoo_test() {
let mut zoo = Zoo::new();
zoo.add(Monkey::new("m1".to_string()));
zoo.add(Limur::new("l1".to_string()));
assert_eq!(zoo.hi_all::<Monkey>(), vec![
"Monkey m1 says: ah ah ah".to_string(),
"Limur l1 says: yo".to_string()
]);
}
However, I'm a bit confused why zoo.hi_all::<Monkey>()
works since it could be either monkey or limur. In other words I don't understand why it works for limur, or am I doing this wrong?
Edit: Here's the code I'm using for src/zoo.rs
:
pub mod animal;
pub mod monkey;
pub mod limur;
use std::collections::VecDeque;
use animal::Animal;
pub struct Zoo<'a> {
list: VecDeque<Box<dyn Animal + 'a>>,
}
impl<'a> Zoo<'a> {
pub fn new() -> Zoo<'a> {
Zoo {
list: VecDeque::new(),
}
}
pub fn add<T>(&mut self, animal: T)
where
T: Animal + 'a,
{
self.list.push_back(Box::new(animal));
}
pub fn hi_all<T>(&self) -> Vec<String>
where
T: Animal + 'a,
{
let mut hi: Vec<String> = vec![];
for animal in &self.list {
if let Some(what) = animal.says() {
hi.push(what);
}
}
hi
}
}
Upvotes: 0
Views: 122
Reputation: 58695
The type variable T
is declared in the type of this function:
pub fn hi_all<T>(&self) -> Vec<String>
where
T: Animal + 'a,
{
let mut hi: Vec<String> = vec![];
for animal in &self.list {
if let Some(what) = animal.says() {
hi.push(what);
}
}
hi
}
but is never actually used in the function's body! Removing that constraint will have no impact because there is no variable of type T
mentioned in the function.
In fact, it never could be used in any practical way, because the elements of the VecDeque
are of a specific concrete type, Box<dyn Animal>
whereas, from the perspective of code inside the function, T
could be any type that implements Animal
.
If you need to filter the animals by type then I suggest you use an enum instead of trait objects, so you can discriminate on the enum variant.
Upvotes: 3