Search code examples
rustcompiler-errorstraits

Storing objects of any type in Rust


I want to implement a class Storage that can store objects of any types. I am trying to do that using trait Any. The Storage::insert::<T>(key, value) should add a pair, where the key is always some String type, and the value can be any type. When I store a Box<HashMap<String, dyn Any>> the compiler says that it doesn't have size at compile-time. So how can I avoid that error ?

use std::any::{Any, TypeId};
use std::collections::hash_map::Keys;
use std::collections::HashMap;

pub struct Storage where Self: Sized{
    map: Box<HashMap<String, dyn Any>>,
}

impl Storage {
    pub fn new() -> Self {
        Self {
            map: Some(Box::new(HashMap::new())),
        }
    }

    pub fn insert<Q: Any>(&mut self, key: &dyn Any, obj: Q) {
        if key.is::<String>() {
            let key_string = key.downcast_ref::<String>().unwrap();
            self.map.as_mut().insert(key_string.clone(), obj);
        }
    }
}

Also I'm not sure that such class can be implemented with std::collections::HashMap


Solution

  • The problem is that HaspMap<K, V> needs to have Sized types K and V, which is not the case of dyn Any. This means that the size of K and V must be known at compile time. For instance, you always know that an u32 will take 32 bits, but the size of [u32] is not known beforehand. Therefore: u32: Sized, and [u32]: !Sized.

    This is also the case of dyn Any, dyn Any: !Sized, because objects of different size can implement Any, and, in fact, every object implements Any.

    To solve this, there is an easy patch, and it's wrapping that type with Box<_>. Box is a pointer to a heap-allocated memory, so you know its size will always be the size of a pointer (roughly speaking), and you don't need to know at compile time how much memory you will allocate on the heap. Here it goes:

    pub struct Storage {
      map: Box<HashMap<String, Box<dyn Any>>>,
    }
    

    You will also have to adapt the rest of the code, but you can find everything in the documentation.