How to store arbitrary struct and recover it as a trait

232 Views Asked by At

How can I store an arbitrary struct and recover it as a trait later?

I do not know the trait that will be requested. In some cases the struct might implement the trait but in others it might not.

I tried the object oriented way by storing the struct as Any and then downcasting it to the trait I need. However, as I understand, it is not possible to do since Rust doesn't have runtime reflection.

use std::{any::Any, collections::HashMap};

pub trait MyTrait {}

pub struct MyStruct {}
impl MyTrait for MyStruct {}

fn main() {
    let my_struct = MyStruct {};
    let as_any: Box<dyn Any> = Box::new(Box::new(my_struct));

    let mut hashmap = HashMap::new();
    hashmap.insert("key", as_any);

    // In this example, I try to downcast to my trait, but it could be an other trait elsewhere in the code.
    match hashmap.get_mut("key").unwrap().downcast::<Box<dyn MyTrait>>() {
        Some(_) => println!("Casting worked"),
        None => println!("Casting failed")
    }
}

Edit: Adding a little bit more details. This is for a library, I don't know in advance the traits or the structs that will be stored in the HashMap.

1

There are 1 best solutions below

1
Pablo Jesús García Fernández On

you can do something like that by using enums:

use std::any::Any;
use std::collections::HashMap;

pub enum MyEnum {
    MyTrait(Box<dyn MyTrait>),
    Any(Box<dyn Any>),
}

pub trait MyTrait {}

pub struct MyStruct {}
impl MyTrait for MyStruct {}

fn main() {
    let my_struct = MyStruct {};
    // let as_any: Box<dyn Any> = Box::new(Box::new(my_struct));

    let mut hashmap = HashMap::new();
    hashmap.insert("key", MyEnum::MyTrait(Box::new(my_struct)));

    // In this example, I try to downcast to my trait, but it could be an other trait elsewhere in the code.
    match hashmap.get_mut("key") {
        Some(my_val) => match my_val {
            MyEnum::MyTrait(_) => println!("its my trait"),
            MyEnum::Any(_) => println!("something else"),
        },
        None => println!("doesn't exist"),
    }
}