Reputation: 571
I have a function that takes a sequence of trait objects and iterates through it multiple times, e.g.,
trait Animal {
fn make_noise(&self);
}
fn make_lots_of_noises(animals: &[&dyn Animal]) {
animals.iter().for_each(|animal| animal.make_noise());
animals.iter().for_each(|animal| animal.make_noise());
animals.iter().for_each(|animal| animal.make_noise());
}
But I want the function to be able to operate on both borrowed and owned data structures. Here are the options I tried:
&[&dyn Animal]
as shown in the code fragment. Problem: if I have owned trait objects, e.g., animals: &[Box<dyn Animal>]
, then I have to call make_lots_of_noises(animals.map(Box::as_ref).collect::<Vec<_>>().as_slice()
, which involves unnecessary allocation on the heap.
&[&R] where R: AsRef<dyn Animal> + ?Sized
. Problem: T
doesn't implement AsRef<T>
! It now works with all kinds of smart pointers, but not &[&dyn Animal]
.
Upvotes: 0
Views: 71
Reputation: 43743
Use the Borrow
trait, which does have the impl Borrow<T> for T
you want.
use std::borrow::Borrow;
trait Animal {
fn make_noise(&self);
}
struct Mouse;
impl Animal for Mouse {
fn make_noise(&self) { /* squeak */ }
}
fn make_lots_of_noises<A: Borrow<dyn Animal>>(animals: &[A]) {
animals.iter().for_each(|animal| animal.borrow().make_noise());
animals.iter().for_each(|animal| animal.borrow().make_noise());
animals.iter().for_each(|animal| animal.borrow().make_noise());
}
fn main() {
make_lots_of_noises(&[&Mouse as &dyn Animal]);
make_lots_of_noises(&[Box::new(Mouse) as Box<dyn Animal>]);
}
Upvotes: 2