-2

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

  • You need to wrap the dyn YourTrait with Box not the whole Hashmap. – Deepthought Apr 18 '22 at 11:04
  • Does this answer your question? [How do I create a heterogeneous collection of objects?](https://stackoverflow.com/questions/27957103/how-do-i-create-a-heterogeneous-collection-of-objects) – Chayim Friedman Apr 26 '22 at 00:20
  • There are bunch of other duplicates [here](https://stackoverflow.com/questions/67475692/the-size-for-values-of-type-dyn-dog-cannot-be-known-at-compilation-time-and-ot). – Chayim Friedman Apr 26 '22 at 00:20

1 Answers1

0

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.

jthulhu
  • 7,223
  • 2
  • 16
  • 33
  • I seem to understand. Your answer gave me a lot of insight. Previously I have implemented a class using Box and now I understand why it worked there and doesn't work here with Box. Thanks a lot! – Yakobs Saghatelyan Apr 18 '22 at 11:50