rust / intermediate
Snippet
HashMap with Custom Key Types: Implementing Eq and Hash
To use a custom type as a HashMap key, you must implement three traits: PartialEq for equality comparison, Eq to assert transitive equality (required when PartialEq is implemented), and Hash to generate a hash value for the hasher. The hash should combine all fields that factor into equality—if two Person structs are equal, they must hash the same. This pattern enables struct-based keys instead of just primitive types.
snippet.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
use std::collections::HashMap;use std::hash::{Hash, Hasher};use std::fmt;#[derive(Debug)]struct Person {name: String,age: u8,}impl PartialEq for Person {fn eq(&self, other: &Self) -> bool {self.name == other.name && self.age == other.age}}impl Eq for Person {}impl Hash for Person {fn hash<H: Hasher>(&self, state: &mut H) {self.name.hash(state);self.age.hash(state);}}impl fmt::Display for Person {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {write!(f, "{} ({})", self.name, self.age)}}fn main() {let mut people: HashMap<Person, &str> = HashMap::new();let alice = Person { name: String::from("Alice"), age: 30 };let bob = Person { name: String::from("Bob"), age: 25 };people.insert(alice, "Engineer");people.insert(bob, "Designer");let lookup = Person { name: String::from("Alice"), age: 30 };if let Some(&profession) = people.get(&lookup) {println!("Alice is an {}", profession);}println!("Total people: {}", people.len());}
Breakdown
1
impl PartialEq for Person {
Defines equality based on both name and age fields
2
impl Eq for Person {}
Eq is a marker trait asserting no NaN-like edge cases
3
self.name.hash(state); self.age.hash(state);
Both fields contribute to hash—order matters for consistency
4
people.get(&lookup)
Creating a new Person with same values successfully looks up the entry