Building a simple HashMap in Rust. Follows live stream done by Jon Gjengset.
The HashMap currently supports a subset of the standard library HashMap's implementations:
- Methods:
new
bucket
entry
insert
get
contains_key
remove
resize
len
is_empty
- Traits:
Index
From
IntoIterator
FromIterator
- Methods:
or_insert
or_insert_with
or_default
- Map structure:
BUCKETS ----- ------- | 0 | -> | k,v | ----- ------------- | 1 | -> | k,v | k,v | ----- ------------- | 2 | -> ----- ------- | 3 | -> | k,v | ----- ------------------------- | 4 | -> | k,v | k,v | k,v | k,v | ----- ------------------------- . . . k,v: key value pair
- HashMap created by
new
method should not allocate any memory. It will be of capacity 0. - Map will be resized when it is either empty or 3/4 full. On every resize we double the capacity.
- Key must implement
Hash + Eq
.Hash
required so that key can be hashed and mapped to a bucket number.Eq
is required so that it can be checked if map contains an (key, value) entry or not. - If
insert
method is called and the key is already present, usestd::mem::replace
. Withreplace
, owning the values or expecting them to beClone
able is not required. get
operation should be generic over the underlying key data. If key is of typeString
, we should be able to get with type&str
. If the owned key type is K, thenget
should be generic over Q such thatK: Borrow <Q>
andQ: [whatever K is required to have]
.- Use
Vec::swap_remove
to efficiently remove an entry inremove
method. IntoIterator::into_iter
returns a type that implementsIterator::next
. IntoIterator implementation for map exists for a ref to map... IntoIterator for &'a HashMap<K, V>
and owned map... IntoIterator for HashMap<K, V>
.- To manage lifetimes while implementing
entry
method, determine theEntry
type first (whetherEntry::Occupied
orEntry::Vacant
) and then return relevant type. (This wayunsafe
usage can be avoided. Implementation in livestream usesunsafe
)
- Idea of building a library through example.
- This is very much like doing TDD. Think how user of the library will use it and develop from there. This will force you to think hard about the features and non-features and make the scope very concrete.
- We can directly take the example that rust docs list for std::collections::HashMap!
- Jon: "You should have trait bounds on the methods rather on the data structures themselves."
- Standard implementation of HashMap only applies trait bounds on the implementation and not on the type.
- What is difference between
&
andref
?- In destructuring subpatterns the
&
operator can't be applied to the value's fields.ref
s objective is exclusively to make the matched binding a reference, instead of potentially copying or moving what was matched. See source.
- In destructuring subpatterns the
unreachable!()
-> is a neat macro that will just throw the error when it is invoked.- Generics + Lifetimes?
- Rust book ch 10.