Hash Maps

Like in many programming languages, hash maps in Rust are data structures that associate keys to values in a linear list of pairs. Accessing a value in a hash map via its corresponding key is an extremely efficient and computationally inexpensive process.

In a similar manner to vectors, hash maps can be initialised with their constructor method new():

Unlike vectors, however, as can be seen on the first line of the above example, hash maps may not immediately be available, and may need to be imported from the collections module in the standard crate.


    

For the sake of clarity when working with hash maps, the type of the data structure can be specified (the above example creates a hash map with integer keys and string slice values), but this is ultimately not required for the compiler to infer the type of the hash map.

The hash map struct has many methods implemented for it to simplify the process of working with this data structure, such as get(K), which takes a key K and returns a reference for its value, if it exists:

In order to handle the possibility of accessing a key that doesn't exist, this method returns an Option that needs to be unwrapped (explained in the chapter on error handling). Additionally, as can be seen in both this example and the previous example, many methods that make accesses to hash maps expect a reference to a numerical index rather than an actual numerical value.


    

Rust hash map structs have three particularly useful built-in methods that allow for iterations over specific parts of the hash map: keys(), values() and iter().

keys() allows for exclusive iteration over the hash map's keys, and values() offers the same for the hash map's values:

Note that keys() and values() return their results in a random order every time they are used.


    

iter() returns all key-value pairs in the hash map, while iter_mut() returns a mutable reference to the value of each pair, which can be very helpful if any edits need to be made to the values in respect to the keys:

iter() and iter_mut() also return their elements in a random order.


    

As a side note, notice that in this example, each value being edited needs to be dereferenced with an asterisk (*). Where referencing a variable is done with an ampersand (&), and allows for that variable to be used elsewhere in memory by passing its address, dereferencing is the opposite of this process, using the memory address contained in a reference to access the original variable.

This syntax will likely be familiar to those with previous C or C++ experience. Rust occasionally makes use of dereferencing syntax in more advanced contexts, but since those mostly go beyond the limits of this introductory course's scope, this should be enough information on C-like dereferencing.

Exercise:
Define a function get_reverse() for the hash map below that, given a hash map and a &str value, returns its i32 key, or zero if the key can't be found:


    


Hint: if you use iter_mut(), you may have to dereference the keys and values being iterated over! Pay close attention to any error messages, many of them will offer direct inline fixes.