Well3
Well3

Reputation: 137

How can I derive Hash for a struct containing a HashMap?

I'm trying to declare a struct which contains a HashMap, but it won't let me derive Hash.

use std::collections::HashMap;

#[derive(PartialEq,Eq,Hash)]
struct Environment{
    names:HashMap<String,String>,
} 

Upvotes: 3

Views: 1397

Answers (1)

cdhowie
cdhowie

Reputation: 169328

HashMap itself does not implement Hash, so an automatic derivation is impossible. You would need to implement Hash manually. Note that you have to be careful to ensure that a manual implementation is compatible with the PartialEq implementation of HashMap; for example, you would need to ensure that you hash key-value pairs in a consistent order, because key order is irrelevant to the PartialEq implementation.

One possible implementation collects all (key, value) pairs into a vector, sorts it on key, and hashes the resulting vector:

impl Hash for Environment {
    fn hash<H: Hasher>(&self, h: &mut H) {
        let mut pairs: Vec<_> = self.names.iter().collect();
        pairs.sort_by_key(|i| i.0);
        
        Hash::hash(&pairs, h);
    }
}

Note that this requires allocating a vector of self.len() elements, but does not require duplicating the strings (they are borrowed).


Consider instead using BTreeMap<String, String>. This type implements Hash, so automatic derivation of Hash is possible:

#[derive(PartialEq, Eq, Hash)]
struct Environment{
    names: BTreeMap<String, String>,
}

Upvotes: 5

Related Questions