Collections: Vectors, Strings, and HashMaps

Learn to use common collection types like Vectors (resizable arrays), Strings (UTF-8 encoded text), and HashMaps (key-value pairs).


Rust HashMaps Explained

Collections: HashMaps

In Rust, like in many other programming languages, a HashMap is a data structure that stores data in key-value pairs. It's a type of collection, which means it can hold multiple values. Unlike arrays or vectors where you access elements using an index (a number), you access elements in a HashMap using a key.

The power of HashMaps lies in their efficiency for looking up values. Instead of searching through a list, the HashMap uses a special function called a hash function to calculate the location of a value based on its key. This allows for very fast retrieval of data, on average, much faster than linear search.

Understanding HashMaps and Key-Value Pairs in Rust

What are Key-Value Pairs?

A key-value pair is the fundamental building block of a HashMap. Think of it like a dictionary:

  • Key: The "word" you're looking up. In a HashMap, keys must be unique within that HashMap.
  • Value: The "definition" of the word. This is the data you want to store and retrieve.

For example, you might have a HashMap that stores student grades. The student's name could be the key, and their grade could be the value.

Creating a HashMap

To use a HashMap, you first need to bring it into scope using the use keyword. Then, you can create a new, empty HashMap using HashMap::new(). You also typically need to specify the types of the key and the value.

 use std::collections::HashMap;

fn main() {
    let mut student_grades: HashMap<&str, i32> = HashMap::new();
} 

In this example:

  • use std::collections::HashMap; imports the HashMap type.
  • let mut student_grades: HashMap<&str, i32> = HashMap::new(); creates a mutable HashMap named student_grades.
  • &str is the type of the key (a string slice).
  • i32 is the type of the value (a 32-bit integer).

Inserting Data into a HashMap

You can insert data into a HashMap using the insert() method. It takes two arguments: the key and the value.

 use std::collections::HashMap;

fn main() {
    let mut student_grades: HashMap<&str, i32> = HashMap::new();

    student_grades.insert("Alice", 90);
    student_grades.insert("Bob", 85);
    student_grades.insert("Charlie", 78);
} 

This code inserts three key-value pairs:

  • "Alice" (key) with 90 (value)
  • "Bob" (key) with 85 (value)
  • "Charlie" (key) with 78 (value)

Retrieving Data from a HashMap

You can retrieve data from a HashMap using the get() method. It takes the key as an argument and returns an Option<&V>, where V is the value type. The Option type represents either Some(value) if the key exists, or None if the key does not exist.

 use std::collections::HashMap;

fn main() {
    let mut student_grades: HashMap<&str, i32> = HashMap::new();

    student_grades.insert("Alice", 90);
    student_grades.insert("Bob", 85);

    let alice_grade = student_grades.get("Alice");
    let david_grade = student_grades.get("David");

    println!("Alice's grade: {:?}", alice_grade); // Output: Alice's grade: Some(90)
    println!("David's grade: {:?}", david_grade); // Output: David's grade: None

    // Safely access the value using match:
    match student_grades.get("Alice") {
        Some(grade) => println!("Alice's grade is: {}", grade),
        None => println!("Alice's grade is not found"),
    }

    // Or using if let:
    if let Some(grade) = student_grades.get("Bob") {
        println!("Bob's grade is: {}", grade);
    } else {
        println!("Bob's grade is not found");
    }
} 

It's important to handle the Option type to avoid errors if the key doesn't exist. The example demonstrates using match and if let for safe access.

Deleting Data from a HashMap

You can remove data from a HashMap using the remove() method. It takes the key as an argument and returns an Option<V>, where V is the value type that was removed. The Option type represents either Some(value) if the key existed and was removed, or None if the key did not exist.

 use std::collections::HashMap;

fn main() {
    let mut student_grades: HashMap<&str, i32> = HashMap::new();

    student_grades.insert("Alice", 90);
    student_grades.insert("Bob", 85);

    let removed_grade = student_grades.remove("Alice");
    println!("Removed Alice's grade: {:?}", removed_grade); // Output: Removed Alice's grade: Some(90)

    let removed_grade_david = student_grades.remove("David");
    println!("Removed David's grade: {:?}", removed_grade_david); // Output: Removed David's grade: None

    println!("Student grades: {:?}", student_grades); // Output: Student grades: {"Bob": 85}
} 

This code removes "Alice" from the HashMap. After the remove() call, the HashMap only contains the key-value pair for "Bob".