Search code examples
rusthashtableownership

Implement `Copy` trait for `Option<Box<Struct>>`


I'm trying to implement a simple hash table with external chaining in Rust but having trouble with the table declaration. I declared the table as such:

static mut _HASH_TABLE: [Option<Box<MemoryMap>>; (std::u16::MAX -1) as usize] = [None; (std::u16::MAX -1) as usize];

with the MemoryMap being a dynamic linked list

pub struct MemoryMap {
    entry: SimpleEntry,
    next: Option<Box<MemoryMap>>,
}

impl MemoryMap {
    pub fn new(init_key: String, init_value: Box<dyn Storable>) -> MemoryMap {
        MemoryMap {
            entry: SimpleEntry::new(init_key, init_value),
            next: None,
        }
    }
//...
}

pub struct SimpleEntry {
    key: String,
    value: Box<dyn Storable>,
}

impl SimpleEntry {
    pub fn new(key: String, value: Box<dyn Storable>) -> SimpleEntry {
        SimpleEntry { key, value }
    }
//...
}

That said, I get this error

5 | static mut _HASH_TABLE: [Option<Box<MemoryMap>>; (std::u16::MAX -1) as usize] = [None; (std::u16::MAX -1) as usize];
  |                                                                                                                                                           ^^^^ the trait `Copy` is not implemented for `Box<MemoryMap>`
  |
  = note: required for `Option<Box<MemoryMap>>` to implement `Copy`
  = note: the `Copy` trait is required because this value will be copied for each element of the array

and I can't understand why elements of the arrays have to be copied since I was expecting the array taking ownership of the Box<MemoryMap>


Solution

  • I can't understand why elements of the arrays have to be copied since I was expecting the array taking ownership of the Box<MemoryMap>

    When you write

    [None; (std::u16::MAX -1) as usize]
    

    the system needs to take the one value you gave it, and duplicate it std::u16::MAX - 1 times in order to fill the array. To do that, it uses Copy:

    A repeat expression [x; N], which produces an array with N copies of x. The type of x must be Copy.

    That can not work here because even if the None value is trivial, as far as Rust is concerned Option<T> implements Copy iff T implements Copy, and Box<_> does not implement Copy. So you need to implement an alternate initialisation method. Like the one linked by @cafce25, or using once_cell / lazy_static in order to have a global which is (lazy-) initialised at runtime, and would likely be something like a Vec.

    Though frankly I don't get why you're even creating a global mutable thing, let alone one initialised a fixed 65k entries (of 64 bit pointers).