I tried the following code:
trait TraitA {
fn say_hello(&self) {
self.say_hello_from_a();
}
fn say_hello_from_a(&self);
}
trait TraitB {
fn say_hello(&self) {
self.say_hello_from_b();
}
fn say_hello_from_b(&self);
}
struct MyType {}
impl TraitA for MyType {
fn say_hello_from_a(&self) {
println!("Hello from A");
}
}
impl TraitB for MyType {
fn say_hello_from_b(&self) {
println!("Hello from B");
}
}
fn main() {
let a: Box<dyn TraitA> = Box::new(MyType {});
let b: Box<dyn TraitB>;
a.say_hello();
b = a;
b.say_hello();
}
I get the following compilation error:
error[E0308]: mismatched types
--> src/main.rs:34:9
|
34 | b = a;
| ^ expected trait `TraitB`, found trait `TraitA`
|
= note: expected struct `std::boxed::Box<dyn TraitB>`
found struct `std::boxed::Box<dyn TraitA>`
I declared two traits and a type called MyType
and implemented both traits for MyType
. I created a new trait object TraitA
of type MyType
which I called a
. Since a
also implements TraitB
, I thought it should be able to be casted as TraitB
.
I haven't figured out if it's even possible. If it is, how can I cast trait object a
into TraitB
?
In C++, I would use something similar to std::dynamic_pointer_cast<TraitB>(a);
for the same purpose.
Here's an example of a case where I could use lateral casting: I have a struct with some data inside that represents some real life entity:
struct MyType {
a: i32,
b: i32,
}
Instances of this type can be used in at least two different parts of the code base. On both parts I need a behavior called get_final_value
.
The interesting part is that get_final_value
should respond differently depending on who called it.
Why don't I split the type into two different ones?: Technically, by design,
a
andb
belong together, not to say thatget_final_value()
uses both values to compute the result.Why not use generics/static dispatch? Because
MyType
is just one example. In the real case I have different structs, all of them implementing both traits in different ways.Why not use
Any
trait? To be honest, I didn't know of it's existence until recently. I don't recall The Rust Programming Language mentioning it. Anyway, it seems you need to know the concrete type to do a cast fromAny
to that concrete type and then to the trait object.