How to get a reference to a concrete type from a trait object?

ghz 7months ago ⋅ 128 views

How do I get Box<B> or &B or &Box<B> from the a variable in this code:

trait A {}

struct B;
impl A for B {}

fn main() {
    let mut a: Box<dyn A> = Box::new(B);
    let b = a as Box<B>;
}

This code returns an error:

error[E0605]: non-primitive cast: `std::boxed::Box<dyn A>` as `std::boxed::Box<B>`
 --> src/main.rs:8:13
  |
8 |     let b = a as Box<B>;
  |             ^^^^^^^^^^^
  |
  = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait

Answers

You cannot directly cast a Box<dyn A> to a Box<B> because Rust does not allow non-primitive casts like this. However, you can achieve what you want by using the downcast method provided by the Any trait, which allows dynamic casting of trait objects to concrete types.

Here's how you can modify your code to achieve the desired behavior:

use std::any::Any;

trait A {}

struct B;
impl A for B {}

fn main() {
    let mut a: Box<dyn A> = Box::new(B);

    // Attempt to downcast the trait object to a concrete type
    let b = match a.downcast::<B>() {
        Ok(b) => b,
        Err(_) => panic!("Failed to downcast to B"),
    };

    // Now `b` is a Box<B>
    let b: Box<B> = Box::new(*b);
}

In this code:

  • We use the downcast method on the trait object a to attempt to downcast it to B.
  • If the downcast is successful, b will contain the boxed value of type B.
  • If the downcast fails, Err will be returned, and we panic with an error message.