What is a HashMap in Rust?

A HashMap is like a real-world dictionary where you look up a word (key) to find its meaning (value). In Rust, a HashMap stores data in key-value pairs, where each key must be unique. It is defined as:

HashMap<K, V>
  • K → Type of the key (like String, i32, etc.)
  • V → Type of the value (like String, f64, etc.)

Every key is unique; you can’t have two keys that are the same. Keys and values can be any data type, as long as they follow Rust’s Eq and Hash rules.

Simple example:

use std::collections::HashMap;

fn main() {
let mut scores = HashMap::new();

// Insert key-value pairs
scores.insert("Alice", 95);
scores.insert("Bob", 88);
scores.insert("Charlie", 100);

// Access a value by its key
if let Some(score) = scores.get("Alice") {
println!("Alice's score is: {}", score);
}

// Print all key-value pairs
for (name, score) in &scores {
println!("{} -> {}", name, score);
}
}

Output:

Alice's score is: 95
Alice -> 95
Bob -> 88
Charlie -> 100
  • In this code, a HashMap is a box that stores pairs like “Alice” -> 95, and the keys (“Alice”, “Bob”, ” Charlie”) are unique identifiers.

Why Use a HashMap?

A HashMap is one of the most useful data structures in Rust, and we use it when we want to store, search, and update data quickly based on a unique key.

  1. Key-Value Pair Storage: HashMap allows you to connect one piece of data (key) with another (value), just like storing someone’s name and their phone number or a student’s name and their grade.
  2. Fast Access: HashMap uses a hashing algorithm internally, which makes searching for a value by its key very fast, usually in constant time O(1).
  3. Flexible Keys and Values: You’re not limited to using simple String or i32. You can store any type as keys or values, even your own custom structs

How To Create a HashMap In Rust?

To use HashMaps, you need to include the std: :collections module.

1. Using HashMap: :new – (Create Empty, Then Add Data)

This is like buying an empty notebook and writing names and marks into it later.

  • HashMap: :new() creates an empty HashMap.
  • insert(key, value) adds data into it.
  • The mut keyword is used because we are modifying the HashMap.

For example:

use std::collections::HashMap;

fn main() {
// Create an empty HashMap to store city names and their populations
let mut city_population = HashMap::new();

// Add data to it
city_population.insert("Delhi", 19800000);
city_population.insert("Tokyo", 37400000);
city_population.insert("Paris", 11000000);

// Display the data
println!("City populations: {:?}", city_population);
}

Output:

City populations: {"Tokyo": 37400000, "Delhi": 19800000, "Paris": 11000000}
  • Here you can see that we created an empty HashMap named city_population and then inserted city names (keys) and their populations (values) one by one.

2. Using from() or collect() – (Create With Data Immediately)

This is like buying a notebook that already has notes written inside.

Example code:

use std::collections::HashMap;

fn main() {
// Create a HashMap with predefined country-capital pairs
let countries: HashMap<&str, &str> =
[("India", "New Delhi"), ("Japan", "Tokyo"), ("France", "Paris")]
.into_iter()
.collect();

// Display the HashMap
println!("Countries and Capitals: {:?}", countries);
}

Output:

Countries and Capitals: {"Japan": "Tokyo", "India": "New Delhi", "France": "Paris"}
  • In this code, we directly created a HashMap of countries with data already present, so there is no need to use .insert() later.

How To Access Values in a HashMap?

We can easily access a value using the following methods. Rust provides two main ways to access values from a HashMap:

1) .get() Method

Get() method returns an Option<&V>. It means it gives you a value (Some) or nothing (None) if the key doesn’t exist.

Code example:

use std::collections::HashMap;

fn main() {
// Create a HashMap storing student names and their grades
let mut grades = HashMap::new();
grades.insert("Amit", 88);
grades.insert("Sneha", 92);

// Try to access a grade safely using .get()
match grades.get("Sneha") {
Some(&marks) => println!("Sneha's grade is {}", marks),
None => println!("No grade found for Sneha"),
}

// Try accessing a key that doesn’t exist
match grades.get("Rahul") {
Some(&marks) => println!("Rahul's grade is {}", marks),
None => println!("No grade found for Rahul"),
}
}

Output:

Sneha's grade is 92
No grade found for Rahul

Explanation:

  • When the key “Sneha” is present, .get() returns Some(92).
  • When “Rahul” is not present, .get() returns None, so we can safely handle it.

2) Direct Indexing

We can also access a value by using square brackets [ ] just like an array. But if the key doesn’t exist, the program will crash.

Simple code example:

use std::collections::HashMap;

fn main() {
// Create a HashMap of fruits and their prices
let mut prices = HashMap::new();
prices.insert("Apple", 120);
prices.insert("Banana", 60);

// Access values directly using indexing
println!("Price of Apple: {}", prices["Apple"]);
println!("Price of Banana: {}", prices["Banana"]);

// This will panic because "Mango" key does not exist
// println!("Price of Mango: {}", prices["Mango"]);
}

Output:

Price of Apple: 120
Price of Banana: 60

How To Modify a HashMap?

We can modify values or add/remove entries in a HashMap.

1) Adding or Updating a Value

The .insert(key, value) method updates the value if the key already exists, and adds a new pair if the key doesn’t exist.

Code example:

use std::collections::HashMap;

fn main() {
let mut marks = HashMap::new();

// Add a new student
marks.insert("Neha", 78);

// Update Neha's marks
marks.insert("Neha", 88);

// Add another student
marks.insert("Karan", 91);

println!("{:?}", marks); // Output: {"Neha": 88, "Karan": 91}
}

2) Updating Only if Key Exists

If you don’t want to overwrite an existing value accidentally, use .entry(), or _insert(). For example:

use std::collections::HashMap;

fn main() {
let mut attendance = HashMap::new();

attendance.insert("Rahul", 22); // Already has attendance recorded

// Will NOT change Rahul's attendance since he already exists
attendance.entry("Rahul").or_insert(30);

// Will insert a new entry since "Priya" doesn't exist
attendance.entry("Priya").or_insert(25);

println!("{:?}", attendance); // Output: {"Rahul": 22, "Priya": 25}
}

3) Removing a Key

We can use .remove(key) to delete a key-value pair from the HashMap. It’s like erasing a student’s record from your notebook.

use std::collections::HashMap;

fn main() {
let mut library = HashMap::new();

library.insert("Book A", 5);
library.insert("Book B", 3);
library.insert("Book C", 8);

// Remove Book B from the library records
library.remove("Book B");

println!("{:?}", library); // Output: {"Book A": 5, "Book C": 8}
}

Iterating Over a HashMap

Iteration means going through each item in a collection one by one.

Simple example:

use std::collections::HashMap;

fn main() {
let mut marks = HashMap::new();

// Adding student names with their marks
marks.insert("Arjun", 88);
marks.insert("Meera", 92);
marks.insert("Rahul", 75);

// Iterating through each key-value pair
for (student, score) in &marks {
println!("Student: {} | Score: {}", student, score);
}
}

Output:

Student: Arjun | Score: 88
Student: Meera | Score: 92
Student: Rahul | Score: 75

Important HashMap Operations

A HashMap is powerful not only for storing key-value pairs but also for managing them easily.

1) Checking Key Existence

Before you try to use a value, it’s often a good idea to check if the key actually exists. Rust provides a simple method: .contains_key(), which returns a boolean (true or false).

Code example:

use std::collections::HashMap;

fn main() {
let mut marks = HashMap::new();
marks.insert("Riya", 95);
marks.insert("Aman", 82);

// Check if "Riya" is present
if marks.contains_key("Riya") {
println!("Riya's marks are recorded!");
} else {
println!("Riya is not found in the record.");
}

// Check a missing key
println!("Is 'Sam' present? {}", marks.contains_key("Sam"));
}

2) Clearing a HashMap

We can use the .clear() method to remove everything from our HashMap.

For example:

use std::collections::HashMap;

fn main() {
let mut products = HashMap::new();
products.insert("Laptop", 55000);
products.insert("Phone", 30000);

println!("Before clearing: {:?}", products);

// Remove all entries
products.clear();

println!("After clearing: {:?}", products);
}

Output:

Before clearing: {"Laptop": 55000, "Phone": 30000}
After clearing: {}

3) Merging HashMaps

We can use the .extend() method to combine two HashMaps at once.

use std::collections::HashMap;

fn main() {
let mut online_store = HashMap::new();
online_store.insert("Headphones", 1500);
online_store.insert("Keyboard", 1200);

let mut offline_store = HashMap::new();
offline_store.insert("Monitor", 8000);
offline_store.insert("Mouse", 600);

// Merge offline store items into online store
online_store.extend(offline_store);

println!("Combined Product List: {:?}", online_store);
}

Output:

Combined Product List: {"Headphones": 1500, "Keyboard": 1200, "Monitor": 8000, "Mouse": 600}

Learn More About Rust Programming

Leave a Comment