#Data Structures

Rust's standard library provides a rich set of collection types. Choosing the right one depends on your access patterns, ordering requirements, and performance constraints.

#Vec — The Workhorse

Vec<T> is a growable array and the most commonly used collection:

let mut numbers = vec![1, 2, 3, 4, 5];

numbers.push(6);
numbers.extend([7, 8, 9]);

let sum: i32 = numbers.iter().sum();
println!("Sum: {sum}");

let evens: Vec<_> = numbers.iter().filter(|number| *number % 2 == 0).collect();
println!("Evens: {evens:?}");

#Pre-allocating Capacity

When you know the approximate size in advance, pre-allocate to avoid repeated reallocations:

let mut buffer = Vec::with_capacity(1024);
for index in 0..1024 {
    buffer.push(index);
}

#HashMap — Key-Value Pairs

HashMap<K, V> provides O(1) average-case lookups:

use std::collections::HashMap;

let mut scores: HashMap<String, u32> = HashMap::new();

scores.insert("Alice".to_string(), 95);
scores.insert("Bob".to_string(), 87);
scores.insert("Charlie".to_string(), 92);

if let Some(score) = scores.get("Alice") {
    println!("Alice scored {score}");
}

scores.entry("Dave".to_string()).or_insert(0);

#Counting Occurrences

A common pattern for counting items:

use std::collections::HashMap;

fn word_frequencies(text: &str) -> HashMap<&str, usize> {
    let mut frequencies = HashMap::new();
    for word in text.split_whitespace() {
        *frequencies.entry(word).or_insert(0) += 1;
    }
    frequencies
}

#BTreeMap — Sorted Keys

When you need keys in sorted order, use BTreeMap:

use std::collections::BTreeMap;

let mut timeline = BTreeMap::new();
timeline.insert(2015, "Rust 1.0 released");
timeline.insert(2018, "Rust 2018 edition");
timeline.insert(2021, "Rust 2021 edition");

for (year, event) in &timeline {
    println!("{year}: {event}");
}

let recent = timeline.range(2018..);

#HashSet — Unique Values

HashSet<T> stores unique values with O(1) membership testing:

use std::collections::HashSet;

let languages: HashSet<&str> = ["rust", "go", "python", "rust"].into_iter().collect();
assert_eq!(languages.len(), 3);
assert!(languages.contains("rust"));

let systems: HashSet<&str> = ["rust", "c", "cpp"].into_iter().collect();

let both = languages.intersection(&systems).collect::<Vec<_>>();
println!("In both sets: {both:?}");

#VecDeque — Double-Ended Queue

VecDeque<T> supports efficient push and pop at both ends:

use std::collections::VecDeque;

let mut queue = VecDeque::new();

queue.push_back("first");
queue.push_back("second");
queue.push_front("zeroth");

while let Some(item) = queue.pop_front() {
    println!("Processing: {item}");
}

#Choosing the Right Collection

CollectionUse When
Vec<T>Ordered sequence, frequent iteration
HashMap<K, V>Fast key-value lookup
BTreeMap<K, V>Sorted key-value pairs, range queries
HashSet<T>Unique values, membership testing
VecDeque<T>Queue or stack behavior
BinaryHeap<T>Priority queue