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());
}