Downcast on &dyn Any vs on Box<dyn Any>

I am trying to implement a collection that stores objects of different types. I can store these objects in a Box<dyn Any> and downcast the object to the proper type. My problem is if first a &dyn Any is extracted from the trait object, then downcast does not work. It compiles, but downcast returns None.

Could anyone explain this?

I narrowed down the code to this:

use std::any::Any;

fn main() {
    let text: String = "text".to_string();
    let component_boxed: Box<dyn Any> = Box::new(text);

    // WORKING when casting the box
    assert!(component_boxed.downcast_ref::<String>().is_some());

    // FAILING when casting the any reference
    let component_ref: &dyn Any = &component_boxed;
    assert!(component_ref.downcast_ref::<String>().is_some());
}

The problem is that Box<dyn Any> implements Any, too, so that component_ref is not the thing you expect. It represents not &String, but &Box<dyn Any>.

To make a reference of the box, you have to dereference it first. Check this:

use std::any::Any;

fn main() {
    let text: String = "text".to_string();
    let component_boxed: Box<dyn Any> = Box::new(text);

    // Downcasting of Box<dyn Any> = Box<String>
    assert!(component_boxed.downcast_ref::<String>().is_some());

    // Downcasting of &dyn Any = &Box<dyn Any>
    let component_ref: &dyn Any = &component_boxed;
    assert!(component_ref.downcast_ref::<Box<dyn Any>>().is_some());
    
    // Downcasting of &dyn Any = &String
    let component_ref: &dyn Any = &*component_boxed;
    assert!(component_ref.downcast_ref::<String>().is_some());
}

Playground

4 Likes

Clear answer. I understand it now.
Thank you!