Add : AsAny
as a superbound for your trait, that will enable downcasting (but forbid types with short-lived borrows, since those are incompatible with checked downcasting), where AsAny
is defined as follows:
trait AsAny : Any {
fn as_any_ref (self: &'_ Self) -> &'_ (dyn Any + 'static)
;
fn as_any_mut (self: &'_ mut Self) -> &'_ mut (dyn Any + 'static)
;
fn into_any_boxed (self: Box<Self>) -> Box<dyn Any + 'static>
;
// feel free to add Rc and Arc as well
}
impl<T : Any> AsAny for T {
fn as_any_ref (self: &'_ Self) -> &'_ (dyn Any + 'static)
{ self }
fn as_any_mut (self: &'_ mut Self) -> &'_ mut (dyn Any + 'static)
{ self }
fn into_any_boxed (self: Box<Self>) -> Box<dyn Any + 'static>
{ self }
// feel free to add Rc and Arc as well
}
- As to why
Any
itself doesn't suffice, it's related to Rust not providing upcasting for free, you have to explicitly ask for it, which is what AsAny
does.
Then, within your code
let _: &'_ (dyn YourTrait + 'static) = thing;
if let Some(instance) = thing.as_any_ref().downcast_ref::<YourStruct>() {
// you get to have access to `YourStruct` _inherent_ logic / data
let _: &YourStruct = instance;
// ...
} else {
// classic impl with no extra data
}
Another (less general) option is, if you only have a limited amount of such types, to add direct downcasting methods to your trait:
trait YourTrait {
// usual stuff
fn downcast_ref (self: &'_ Self) -> Option<&'_ YourStruct>
{
None
}
}
// Later
impl YourTrait for YourStruct {
// ...
fn downcast_ref (self: &'_ YourStruct) -> Option<&'_ YourStruct>
{
Some(self)
}
}
and then you can simply do, with a given thing: &'_ (dyn YourTrait + '_)
:
if let Some(your_struct) = thing.downcast_ref() {
// etc.
Finally, if you don't expect the trait to be implemented for an arbitrarily big number of types (i.e., if you don't need extensionability), you should seriously consider replacing your dyn YourTrait
with an enum
that has all the possible types as variants:
enum DynObject {
YourStruct(YourStruct),
// ...
}
// and later
if let DynObject::YourStruct(your_struct) = thing {
// etc.