Sling Academy
Home/Rust/Collections in Rust: Vectors, HashMaps, and More

Collections in Rust: Vectors, HashMaps, and More

Last updated: January 03, 2025

Rust is a modern system programming language that provides powerful and flexible tools for handling collections of data. In this article, we'll explore various collection types in Rust, focusing mainly on Vec (vectors), HashMap, and more advanced collections available through the Rust standard library and popular crates. These collections are key for effective data storage and manipulation, allowing developers to build high-performance applications.

Vectors

Vectors, represented by Vec<T> in Rust, are dynamic arrays that can store elements of the same type. Vectors are resizable, providing an efficient way to allocate memory when the size of the data isn't known at compile time. Let's see how to create and manipulate vectors in Rust:

fn main() {
    let mut numbers: Vec<i32> = Vec::new();
    numbers.push(1);
    numbers.push(2);
    numbers.push(3);

    println!("Vector: {:?}", numbers);
}

In this example, we declared a mutable vector and pushed three integers into it. The push method adds an element to the end, and the vector resizes dynamically as needed.

Accessing and Iterating Over Vectors

Accessing elements in a vector is done by indexing:

fn main() {
    let numbers = vec![10, 20, 30, 40];
    let second = numbers[1];
    println!("The second element is {}");
}

We use square brackets to get the value at a particular index, which is zero-based. Rust will panic if you try to access an index out of bounds, ensuring memory safety.

Iterating over a vector can be done using loops:

for number in &numbers {
    println!("{}", number);
}

HashMaps

HashMap<K, V> is a key-value store, where each key is associated with exactly one value. This collection is highly suitable for cases where quick access to data with unique keys is necessary.

use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();
    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

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

In this example, we create a mutable HashMap and insert some entries. The String::from is used to convert a string literal into a String type, aligning with the types expected by the HashMap.

Retrieving Values from a HashMap

To retrieve a value, you use the get method, which returns an Option<V>:

fn main() {
    let team_name = String::from("Blue");
    let score = scores.get(&team_name);

    match score {
        Some(&score) => println!("The score for Blue is {}", score),
        None => println!("No score found for team.")
    }
}

In this snippet, get returns Some(value) if the key exists; otherwise, it returns None.

Iterating Over a HashMap

You can iterate through a HashMap using a loop:

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

Other Collection Types

Besides vectors and hash maps, Rust comes with other collection types available in the standard library such as BTreeMap, BTreeSet, and more. These are complimented by popular crates like VecDeque for queue-like functionality and HashSet for sets. These additional collections provide more options to fit the wide array of potential use cases in applications.

Example with BTreeMap

use std::collections::BTreeMap;

fn main() {
    let mut book_reviews = BTreeMap::new();
    book_reviews.insert("The Great Gatsby", "A classic novel");
    book_reviews.insert("1984", "Dystopian novel");
    
    for (book, review) in &book_reviews {
        println!("Book: "{book}, "Review: "{review});
    }
}

The BTreeMap provides keys in sorted order, which can be crucial when order is necessary.

Conclusion

Rust's collection types offer high-performing and memory-safe structures that can enhance application development. Vectors and hash maps serve general needs, while specialized collections like BTreeMap can also play critical roles depending on use cases. Understanding these collections empowers you to utilize Rust’s full potential efficiently to manage data structures in robust applications.

Next Article: Unleashing Rust Slices: Borrowing Portions of Arrays Safely

Previous Article: Iterator Traits in Rust for Efficient Data Processing

Series: Rust Data Types

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