kota's memex

The type HashMap<K, V> stores a mapping of keys of type K to values of type V. Hash maps are useful when you want to look up data not by using an index, as you can with vectors, but by using a key that can be of any type.

HashMap's are not part of the prelude so you need to use them to bring them into scope.

use std::collections::HashMap;

let mut scores = HashMap::new();

scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);

get

The get() method returns an Option<&V>; if there's no key get will return None. This example calls copied() to get an Option<i32> instead of Option<&i32>, then unwrap_or(0) to set the score to 0 if no score is found.

let score = scores.get(&team_name).copied().unwrap_or(0);

looping

The order is random:

for (key, value) in &scores {
    println!("{key}: {value}");
}

inserting

use std::collections::HashMap;

let mut scores = HashMap::new();

scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Blue"), 25);

println!("{scores:?}");

only if missing

It’s common to check whether a particular key already exists in the hash map with a value and then to take the following actions: if the key does exist in the hash map, the existing value should remain the way it is; if the key doesn’t exist, insert it and a value for it.

use std::collections::HashMap;

let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);

scores.entry(String::from("Yellow")).or_insert(50);
scores.entry(String::from("Blue")).or_insert(50);

println!("{scores:?}");

updating a value

Another common use case it looking up a key's value and updating it based on the old value.

use std::collections::HashMap;

let text = "hello world wonderful world";

let mut map = HashMap::new();

for word in text.split_whitespace() {
    let count = map.entry(word).or_insert(0);
    *count += 1;
}

println!("{map:?}");

The and_modify method is frequently chained with or_insert:

scores
    .entry(team_2_name)
    .and_modify(|scores| {
        scores.goals_scored += team_2_score;
        scores.goals_conceded += team_1_score;
    })
    .or_insert(TeamScores {
        goals_scored: team_2_score,
        goals_conceded: team_1_score,
    });

ownership

For types that implement the Copy trait, like i32, the values are copied into the hash map. For owned values like String, the values will be moved and the hash map will be the owner of those values.

use std::collections::HashMap;

let field_name = String::from("Favorite color");
let field_value = String::from("Blue");

let mut map = HashMap::new();
map.insert(field_name, field_value);

println!(field_name); // Compiler error! Value was moved!

hashing algorithm

By default, HashMap uses a hashing function called SipHash that can provide resistance to denial-of-service (DoS) attacks involving hash. This is not the fastest algorithm available; in some cases you may wish to make a different tradeoff and find an alternative hashing algorithm on crates.io.