Sling Academy
Home/Rust/Introduction to Rust’s core collection types: Lists, Vectors, and HashMaps

Introduction to Rust’s core collection types: Lists, Vectors, and HashMaps

Last updated: January 04, 2025

Rust is a systems programming language focused on safety, speed, and concurrency. It provides a variety of collections for storing data, each with its strengths and use cases. Today, we'll explore some of the core collection types that Rust offers: Lists, Vectors, and HashMaps.

Lists

In Rust, a basic list type doesn't exist like in some other programming languages. Instead, the closest counterpart is a linked list, provided through a third-party crate such as linked-list or Rust's standard library std::collections::LinkedList. However, they're not as commonly used in idiomatic Rust programs due to their potential performance costs in certain scenarios.

Using Linked Lists

use std::collections::LinkedList;

fn main() {
    let mut list: LinkedList = LinkedList::new();
    list.push_back(1);
    list.push_back(2);
    list.push_back(3);

    for value in &list {
        println!("{}", value);
    }
}

In the example above, we declare a LinkedList for integers, add some elements to it with push_back, and iterate over the list to print each element. Linked lists are convenient when you need fast inserts and deletes, but they're generally slower for accessing elements compared to other collections like Vectors.

Vectors

Vectors are similar to arrays, but they can grow and shrink in size. They are located in the heap memory and hence have dynamic sizing, which makes them an excellent choice when dealing with collections of variable sizes.

Creating and Modifying Vectors

fn main() {
    let mut v = vec![1, 2, 3];
    v.push(4);
    println!("Vector: {:?}", v);

    v.remove(1);
    println!("After removing element at index 1: {:?}", v);
}

Here, we define a Vector, initially holding integers 1, 2, and 3. We add a 4 using push and remove the element at index 1 using remove. Vectors are the preferred way of working with a contiguous growable collection of items in Rust.

HashMaps

HashMaps provide the functionality to store key-value pairs. They are highly useful when you need to look up data through a key. However, the keys need to be of a type that implements the Hash and Eq traits.

Using HashMaps

use std::collections::HashMap;

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

    scores.insert("Alice", 10);
    scores.insert("Bob", 20);

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

    match scores.get("Alice") {
        Some(value) => println!("Alice's score: {}", value),
        None => println!("Alice's score not found."),
    }
}

In this example, a HashMap is created to store names and scores. We populate it using the insert method and iterate over the key-value pairs to print them. You can also fetch values directly by key using get, which returns an Option.

Conclusion

Understanding and utilizing Rust's core collection types is essential for effective programming in Rust. While LinkedList offers advantages for frequent insertions, Vectors provide flexibility due to their dynamic nature and HashMaps allow for key-value pair management with quick look-up.

With Rust’s powerful ownership system and a robust standard library, these collection types enable safe, concurrent, and powerful data handling unmatched by some of its peers in systems programming.

Next Article: Understanding the difference between contiguous arrays and linked lists in Rust

Series: Collections in Rust

Rust

You May Also Like

  • E0557 in Rust: Feature Has Been Removed or Is Unavailable in the Stable Channel
  • Network Protocol Handling Concurrency in Rust with async/await
  • Using the anyhow and thiserror Crates for Better Rust Error Tests
  • Rust - Investigating partial moves when pattern matching on vector or HashMap elements
  • Rust - Handling nested or hierarchical HashMaps for complex data relationships
  • Rust - Combining multiple HashMaps by merging keys and values
  • Composing Functionality in Rust Through Multiple Trait Bounds
  • E0437 in Rust: Unexpected `#` in macro invocation or attribute
  • Integrating I/O and Networking in Rust’s Async Concurrency
  • E0178 in Rust: Conflicting implementations of the same trait for a type
  • Utilizing a Reactor Pattern in Rust for Event-Driven Architectures
  • Parallelizing CPU-Intensive Work with Rust’s rayon Crate
  • Managing WebSocket Connections in Rust for Real-Time Apps
  • Downloading Files in Rust via HTTP for CLI Tools
  • Mocking Network Calls in Rust Tests with the surf or reqwest Crates
  • Rust - Designing advanced concurrency abstractions using generic channels or locks
  • Managing code expansion in debug builds with heavy usage of generics in Rust
  • Implementing parse-from-string logic for generic numeric types in Rust
  • Rust.- Refining trait bounds at implementation time for more specialized behavior