Polymorphism and maps


#1

Hello

    use std::collections::{HashMap};

    pub trait ContextUnit {}

    #[derive(Debug)]
    pub struct SimpleContextUnit {}

    #[derive(Debug)]
    pub struct ComplexContextUnit {}

    impl ContextUnit for SimpleContextUnit {}

    impl ContextUnit for ComplexContextUnit {}

    #[derive(Debug)]
    pub struct ContextHolder<T: ContextUnit> {
        units: HashMap<String, T>
    }

    fn main() {
        let mut units = HashMap::new();
        units.insert("simple".to_owned(), SimpleContextUnit {});
        //    units.insert("complex".to_owned(), ComplexContextUnit {});
        let immut_units = units;
        let holder = ContextHolder {
            units: immut_units
        };
        println!("{:?}", holder);
    }

How can I reach polymorphism In this example?
If I uncomment the following line:
units.insert("complex".to_owned(), ComplexContextUnit {});
The program will fail.

error[E0308]: mismatched types
  --> src/main.rs:49:40
   |
49 |     units.insert("complex".to_owned(), ComplexContextUnit {});
   |                                        ^^^^^^^^^^^^^^^^^^^^^ expected struct `SimpleContextUnit`, found struct `ComplexContextUnit`
   |
   = note: expected type `SimpleContextUnit`
   = note:    found type `ComplexContextUnit`

In OOP language I can have base class and pass it’s type to map as value.
How can I do it in rust?
P.S the goal is to have a map units: HashMap<String, T> where T: ContextUnit
And pass as a map value any struct that implements ContextUnit
Thanks


#2

I’ve got answer from the rust’s gitter channel https://gitter.im/rust-lang/rust
(thanks to crumblingstatue)
So the solution is to use units: HashMap<String, Box<ContextUnit>> instead.
After you need to provide more about the map key=>value types like following:

let mut units: HashMap<String, Box<ContextUnit>> = HashMap::new();

The complete example:

use std::collections::{HashMap};

pub trait ContextUnit {}

#[derive(Debug)]
pub struct SimpleContextUnit {}

#[derive(Debug)]
pub struct ComplexContextUnit {}

impl ContextUnit for SimpleContextUnit {}

impl ContextUnit for ComplexContextUnit {}

pub struct ContextHolder {
    units: HashMap<String, Box<ContextUnit>>
}

fn main() {
    let mut units: HashMap<String, Box<ContextUnit>> = HashMap::new();
    units.insert("simple".to_owned(), Box::new(SimpleContextUnit {}));
    units.insert("complex".to_owned(), Box::new(ComplexContextUnit {}));
    let immut_units = units;
    let holder = ContextHolder {
        units: immut_units
    };
}