pub struct WidgetWrap {
// ...
widget: RefCell<Box<Any>>,
}
At some point I want to cast Box<Any>
to Box<WidgetTrait>
let mut cell = widget.borrow_mut();
let w = cell.downcast_mut::<Box<WidgetTrait>>();
This gives me an error of this kind:
error: instantiating a type parameter with an incompatible type
`Box<WidgetTrait>`, which does not fulfill `'static` [E0144]
What does this really mean?
I've looked at How to fix: value may contain references; add `'static` bound to `T` and did try adding + 'static
everywhere.
pub struct WidgetWrap {
// ...
widget: RefCell<Box<Any + 'static>>,
}
let mut cell = widget.borrow_mut();
let w = cell.downcast_mut::<Box<WidgetTrait + 'static>>();
It fixes the compile errors, but fails when I try to unwrap the downcasted box as shown above. And yes, the content of the box is an object that implements WidgetTrait
.
Obviously, I am coding in Rust at a level that I don't quite understand, but maybe someone can help me get a better grip on the concepts involved in the above task.
We create a trait object by specifying some sort of pointer, such as a & reference or a Box<T> smart pointer, then the dyn keyword, and then specifying the relevant trait.
rust. Downcasting is Rust's method of converting a trait into a concrete type. It is done using the Any trait, which allows "dynamic typing of any 'static type through runtime reflection" (docs).
A trait object is an opaque value of another type that implements a set of traits. The set of traits is made up of an object safe base trait plus any number of auto traits. Trait objects implement the base trait, its auto traits, and any supertraits of the base trait.
(I shall ignore the 'static
part as it’s comparatively irrelevant for the parts I’m explaining.)
Box<Trait>
for a given trait Trait
is stored as two pieces of data: a pointer to the actual data in memory and a pointer to the vtable for its type’s implementation of Trait
.
From that, you may see that you can only have one level of traityness—if you have a Box<WidgetTrait>
and you box it again as Box<Any>
, you would only be able to get it out as a Box<WidgetTrait>
object. Similarly, if you take a type Widget
that implements WidgetTrait
and box it in a Box<Any>
, you can only get it out as a Widget
object, not as a Box<WidgetTrait>
object.
Such is the nature of the type IDs being used internally: unlike in a dynamic or VM-based language, the type system is purely a compile-time construct; there is no such thing as the type system at runtime.
The solution, if you really need a solution along these lines (you probably don’t; sticking with just a Box<WidgetTrait>
is probably the best way) is to have a trait which also implements what Any
does. This is not the simplest thing at present, but can be done. Teepee’s Header
trait is an example of how this can work; a Box<Header>
object will have the header-transforming methods as well as Any
’s .downcast_ref()
and so forth.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With