Skip to content

Rust HashMaps

A HashMap stores data as key-value pairs — you look things up by a key instead of by position, the way you would with an array or vector. If you’ve used a dictionary in Python or an object-as-map in JavaScript, this is the same idea.

use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alice", 30);
ages.insert("Bob", 25);
println!("{:?}", ages);
}

use std::collections::HashMap; at the top brings the type into scope — unlike Vec and String, HashMap isn’t available by default, so this line is required.

▶ Try it Yourself
use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alice", 30);
match ages.get("Alice") {
Some(age) => println!("Alice is {age}"),
None => println!("Not found"),
}
}
▶ Try it Yourself

.get() returns an Option rather than the value directly, because the key might not exist. We’ll cover Option properly on its own page — for now, match with Some/None is the standard way to handle it.

Inserting again with the same key overwrites the old value:

use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alice", 30);
ages.insert("Alice", 31); // overwrites 30
println!("{:?}", ages.get("Alice"));
}
▶ Try it Yourself

If you only want to insert a value when the key doesn’t already exist, use .entry():

use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alice", 30);
ages.entry("Alice").or_insert(99); // Alice exists, so this does nothing
ages.entry("Bob").or_insert(25); // Bob doesn't exist, so this inserts it
println!("{:?}", ages);
}
▶ Try it Yourself
use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alice", 30);
ages.insert("Bob", 25);
for (name, age) in &ages {
println!("{name} is {age}");
}
}
▶ Try it Yourself

Reach for a HashMap whenever you want to look things up by a name or ID instead of a position — counting word frequency, mapping usernames to user data, caching results by key. If order matters or you’re just working through a plain list, a Vec is the better fit.

Store three names and phone numbers in a HashMap. Then look up "Ben" (who is in it) and "Dana" (who isn’t), and print a friendly line for each. Hint: loop over ["Ben", "Dana"] and match on .get(name).

Show solution
use std::collections::HashMap;
fn main() {
let mut phone_book = HashMap::new();
phone_book.insert("Ana", "555-1234");
phone_book.insert("Ben", "555-9876");
phone_book.insert("Chen", "555-4321");
for name in ["Ben", "Dana"] {
match phone_book.get(name) {
Some(number) => println!("{name}: {number}"),
None => println!("{name}: not in the phone book"),
}
}
}

Output:

Ben: 555-9876
Dana: not in the phone book
▶ Try it Yourself

Looping over the names we want, instead of over the map, also gives us a fixed order. That’s a handy trick whenever you need predictable output from a HashMap.

You have the votes ["red", "blue", "red", "green", "blue", "red"]. Count how many each color got, then print the totals for "red", "green", "blue" and "pink" (which got none). Hint: counts.entry(color).or_insert(0) gives you the current count for that color, starting at 0. Add one to it with *count += 1.

Show solution
use std::collections::HashMap;
fn main() {
let votes = ["red", "blue", "red", "green", "blue", "red"];
let mut counts = HashMap::new();
for color in votes {
let count = counts.entry(color).or_insert(0);
*count += 1;
}
for color in ["red", "green", "blue", "pink"] {
match counts.get(color) {
Some(n) => println!("{color}: {n}"),
None => println!("{color}: 0"),
}
}
}

Output:

red: 3
green: 1
blue: 2
pink: 0
▶ Try it Yourself

or_insert(0) returns a mutable reference to the value stored in the map, not a copy. The * in *count += 1 means “change the number this points to”, so the map itself gets updated. This “entry, or insert 0, then add 1” pattern is the standard way to count things in Rust.

  • HashMap<K, V> stores key-value pairs; bring it into scope with use std::collections::HashMap;.
  • .insert(key, value) adds or overwrites; .get(key) looks up and returns an Option.
  • .entry(key).or_insert(value) inserts only if the key isn’t already there.
  • Iteration order isn’t guaranteed — don’t rely on it.

Quick check

1. What do you need to bring HashMap into scope, unlike Vec or String?

2. What does .entry(key).or_insert(value) do?

3. Can you rely on the order entries print when looping over a HashMap?

Score: 0 / 3