Challenge 7
Spot the bug
Identify why the code fails to compile and suggest a way to fix it.
#![allow(unused)] fn main() { use std::collections::HashMap; struct UInt64Counter<Key> { count_by_key: HashMap<Key, u64>, } impl<Key> UInt64Counter<Key> { fn new() -> Self { UInt64Counter { count_by_key: HashMap::new(), } } fn add(&mut self, key: Key, delta: u64) { *self.count_by_key.entry(key).or_default() += delta; } } }
Solution
Click to Show/Hide Solution
The Bug: Compiler error!
Solution:
The struct UInt64Counter
is generic over the type parameter Key
which is used as the HashMap key.
#![allow(unused)] fn main() { struct UInt64Counter<Key> { count_by_key: HashMap<Key, u64> } }
The add
method increments the counter for the provided key using the entry
method of the HashMap
.
#![allow(unused)] fn main() { fn add(&mut self, key: Key, delta: u64) { *self.count_by_key.entry(key).or_default() += delta; } }
If we look at the entry
method of the HashMap
, it is defined with with a few generic type parameters and one of them is the parameter K, K: Hash+Eq
. This parameter is the key of the HashMap.
#![allow(unused)] fn main() { impl<K, V, S> HashMap<K, V, S> where K: Eq + Hash, S: BuildHasher, { pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { map_entry(self.base.rustc_entry(key)) } } }
This constraint means that the entry
method exists for the HashMap
if the key implements Eq
and Hash
traits. Hence, the compiler gives the error: “the method entry
exists for struct HashMap<Key, u64>
, but its trait bounds were not satisfied”
To solve the compilation error, we must use the constraint Eq + Hash in the generic parameter of UInt64Counter
.
#![allow(unused)] fn main() { struct UInt64Counter<Key: Eq + Hash> { count_by_key: HashMap<Key, u64>, } impl<Key: Eq + Hash> UInt64Counter<Key> { fn new() -> Self { return UInt64Counter { count_by_key: HashMap::new() }; } fn add(&mut self, key: Key, delta: u64) { *self.count_by_key.entry(key).or_default() += delta; } } }