0

I have a trait and a struct that implements that trait:

trait A {
    fn something(&self);
}

struct B {
    some_field: i32,
}

impl A for B {
    fn something(&self) {}
}

There is a part of my code where I have an &A, and I know it is an instance of B, I would like to cast &A to &B. How can I accomplish this? So far, I have tried first casting to *const A and then casting to *const B, but I can't figure out how to go from *const B to &B.

After playing around with some things, I think this is correct?

fn some_func(a: &dyn A) {
    let a_ptr = a as *const A;
    let b_ptr = a_ptr as *const B;
    unsafe { let b = &*b_ptr as &B; }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Max
  • 15,157
  • 17
  • 82
  • 127
  • 4
    "After playing around with some things, I think this is correct?" this is not really how I will call this kind of thing in rust. But yes this will "compile" – Stargateur Sep 09 '18 at 19:53
  • Maybe if you added a bit of the code that produces the `A` we could find a way around the problem. – Aankhen Sep 09 '18 at 20:12
  • 2
    If you have an `&A`, and you *know* it is an instance of `B`, why can't you prove that it is -- i.e., use `&B`? – trent Sep 09 '18 at 21:37
  • @trentcl my code would be provable with tagged unions, but Rust doesn't have such functionality. I could probably use an enum, but that seems like a less fun way to write the code. – Max Sep 10 '18 at 02:17
  • 5
    Sure, "fun" is one way to describe undefined behavior. – trent Sep 10 '18 at 03:01
  • 6
    `enum` is what Rust calls a tagged union… – Jmb Sep 10 '18 at 07:19

1 Answers1

1

One way to do this safely is by adding a method fn any(&self) -> &Any to your trait, which carries type information and makes it possible to perform a checked downcast to an arbitrary type (in this case B).

use std::any::Any;

trait A {
    fn something(&self);
    fn any(&self) -> &Any;
}

struct B {
    some_field: i32,
}

impl A for B {
    fn something(&self) {}
    fn any(&self) -> &Any {
        self
    }
}

fn some_func(a: &dyn A) {
    let b: &B = a.any().downcast_ref().unwrap();
}
dtolnay
  • 9,621
  • 5
  • 41
  • 62