Is it even possible to do so or would I need to take a very different approach?
Calculate::Output
must be the same concrete type (which would include some pointer type to a trait object) for every element in your vector, because dyn Calculate<Output=i32>
is not the same type as dyn Calculate<Output=f64>
and vectors are homogenous, so they can only store elements that all have the same type.
2 Likes
If all of the output types have a common interface, like Display
, you can define a helper trait to make this work:
pub trait Calculate {
type Output: Display;
fn calculate(&self) -> Self::Output;
}
trait CalcForDisplay {
fn calc_for_display(&self)->Box<dyn Display + '_>;
}
impl<T:Calculate + ?Sized> CalcForDisplay for T {
fn calc_for_display(&self)->Box<dyn Display + '_> {
Box::new(self.calculate())
}
}
2 Likes
@2e71828 's method is better!
This is mine ( with std::any
):
pub trait Calculate {
fn calculate(&self) -> Box<dyn Any>;
fn display(&self) {
let ans = self.calculate();
if (*ans).type_id() == TypeId::of::<f64>() {
println!("{}", ans.downcast::<f64>().unwrap());
} else if (*ans).type_id() == TypeId::of::<i32>() {
println!("{}", ans.downcast::<i32>().unwrap());
} else {
unreachable!();
}
}
}
1 Like
You can avoid the double-checking and unwrap
s here by using if let
:
if let Some(x) = ans.downcast_ref::<f64>() {
println!("{}", x);
} else if let Some(x) = ans.downcast_ref::<i32>() {
println!("{}", x);
}
3 Likes