Collections

Rust vectors, HashMaps, HashSets, slices, and iterators — creating, iterating, and transforming

Rust’s standard collections are in std::collections. The most common are Vec, HashMap, and HashSet. All collections own their data — no garbage collector needed.

Vec<T>

Growable array, heap-allocated. The workhorse collection.

// Creating
let mut v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3];                 // macro with type inference
let v = vec![0; 10];                   // ten zeros: [0, 0, 0, ...]

// Push and pop
let mut v = vec![1, 2, 3];
v.push(4);                              // [1, 2, 3, 4]
let last = v.pop();                     // Some(4), v is now [1, 2, 3]

// Access
let v = vec![10, 20, 30];
let first = v[0];                        // 10 — panics if out of bounds
let second = v.get(1);                   // Some(&20) — returns Option
let oob = v.get(10);                     // None — safe access

// Iterate
for item in &v { /* &i32 */ }            // immutable borrow
for item in &mut v { *item += 1; }      // mutable borrow
for item in v { /* i32, v consumed */ }  // take ownership

// Iterate with index
for (i, item) in v.iter().enumerate() {
    println!("{}: {}", i, item);
}

// Splice / drain
let mut v = vec![1, 2, 3, 4, 5];
v.drain(1..3);                           // removes elements at index 1,2

// Extend
let mut v = vec![1, 2];
v.extend([3, 4]);                        // [1, 2, 3, 4]
v.append(&mut vec![5, 6]);              // moves elements, v is now [1, 2, 3, 4, 5, 6]

// Sort
let mut v = vec![3, 1, 2];
v.sort();                                // [1, 2, 3]
v.sort_by(|a, b| b.cmp(a));             // [3, 2, 1] — descending

// Reverse
v.reverse();

// Split
let v = vec![1, 2, 3, 4, 5];
let (left, right) = v.split_at(2);      // ([1, 2], [3, 4, 5])

Strings

Strings in Rust are UTF-8 encoded. String is owned and growable; &str is a borrowed slice.

// Creating
let s = String::from("hello");
let s = "hello".to_string();
let s = format!("hello {}", name);

// Append
let mut s = String::from("hello");
s.push_str(" world");                   // "hello world"
s.push('!');                             // "hello world!"

// Concatenate
let full = String::from("hello") + " world"; // note: left side must be String
let full = format!("{} {}", "hello", "world");

// Iterate
for ch in "hello".chars() { /* char */ }
for b in "hello".bytes() { /* u8 */ }

// Check
s.is_empty();
s.contains("ell");
s.starts_with("hel");
s.ends_with("world");

// Trim
let s = "  hello  ".trim();             // "hello"
let s = "  hello  ".trim_start();        // "hello  "
let s = "  hello  ".trim_end();          // "  hello"

// Split
for word in "hello world".split_whitespace() { }
for part in "a,b,c".split(',') { }
let parts: Vec<&str> = "a,b,c".split(',').collect();

// Replace
let s = "hello world".replace("world", "rust"); // "hello rust"

// Length
s.len();                                 // byte length, NOT character count
s.chars().count();                        // character count (UTF-8 safe)

HashMap<K, V>

Key-value store. Requires use std::collections::HashMap.

use std::collections::HashMap;

// Creating
let mut scores = HashMap::new();
scores.insert("Alice", 10);
scores.insert("Bob", 20);

// From pairs
let teams = vec![("Red", 10), ("Blue", 20)];
let map: HashMap<_, _> = teams.into_iter().collect();

// Access
let score = scores.get("Alice");         // Some(&10)
let score = scores.get("Eve");           // None
let score = scores.get(&"Alice".to_string()); // with owned keys

// Insert (overwrites existing)
scores.insert("Alice", 15);              // overwrites 10

// Insert only if key doesn't exist
scores.entry("Alice").or_insert(5);      // keeps 15 (already exists)
scores.entry("Eve").or_insert(30);       // inserts 30

// Insert and modify
scores.entry("Alice").and_modify(|v| *v += 1).or_insert(1);

// Update pattern — count word frequencies
let mut word_count = HashMap::new();
for word in &words {
    *word_count.entry(word).or_insert(0) += 1;
}

// Remove
scores.remove("Bob");

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

// Keys and values
for key in scores.keys() { }
for value in scores.values() { }
for value in scores.values_mut() { *value += 1; }

// Length and emptiness
scores.len();
scores.is_empty();

HashSet<T>

Unordered collection of unique values. Requires use std::collections::HashSet.

use std::collections::HashSet;

// Creating
let mut set = HashSet::new();
set.insert(1);
set.insert(2);
set.insert(2);                           // duplicate — no effect

let set: HashSet<i32> = [1, 2, 3].into_iter().collect();

// Check membership
set.contains(&1);                        // true
set.contains(&5);                        // false

// Remove
set.remove(&1);                          // true if present

// Iterate
for item in &set { }

// Set operations
let a: HashSet<i32> = [1, 2, 3].into_iter().collect();
let b: HashSet<i32> = [2, 3, 4].into_iter().collect();

let intersection = a.intersection(&b).collect::<HashSet<_>>();  // {2, 3}
let union = a.union(&b).collect::<HashSet<_>>();                 // {1, 2, 3, 4}
let diff = a.difference(&b).collect::<HashSet<_>>();            // {1}
let sym_diff = a.symmetric_difference(&b).collect::<HashSet<_>>(); // {1, 4}

// Subset checks
a.is_subset(&b);                         // false
a.is_superset(&b);                       // false
a.is_disjoint(&b);                       // false

Slices

A slice is a borrowed view into a contiguous sequence. &[T] for arrays/vecs, &str for strings.

// Vec slice
let v = vec![1, 2, 3, 4, 5];
let slice: &[i32] = &v[1..3];            // [2, 3]
let slice: &[i32] = &v[..];               // entire vec as slice
let slice: &[i32] = &v[2..];              // [3, 4, 5]
let slice: &[i32] = &v[..3];              // [1, 2, 3]

// String slice
let s = String::from("hello world");
let hello: &str = &s[0..5];              // "hello"
let world: &str = &s[6..];                // "world"

// Function accepting slice (works with Vec and arrays)
fn sum(slice: &[i32]) -> i32 {
    slice.iter().sum()
}
let v = vec![1, 2, 3];
let a = [1, 2, 3];
sum(&v);                                  // works
sum(&a);                                  // works

Warning: String slicing by byte index can panic on non-ASCII characters. Use .chars() for safe character-based access.

Iterators

Iterators are lazy — they only evaluate when consumed. Chain them for powerful data transformations.

// Creating iterators
let v = vec![1, 2, 3, 4, 5];
v.iter()            // yields &i32 (immutable borrow)
v.iter_mut()        // yields &mut i32 (mutable borrow)
v.into_iter()       // yields i32 (consumes the vec)

// Transform
v.iter().map(|x| x * 2);                          // double each
v.iter().filter(|x| *x > 2);                      // keep > 2
v.iter().filter_map(|x| if *x > 2 { Some(*x) } else { None }); // filter + map
v.iter().enumerate();                               // (index, &value)
v.iter().zip(['a', 'b', 'c'].iter());              // pair elements
v.iter().flat_map(|x| (0..*x));                    // flatten one level

// Combine
v.iter().fold(0, |acc, x| acc + x);               // reduce / sum
v.iter().chain(vec![6, 7].iter());                  // chain iterators
v.iter().take(3);                                    // first 3 elements
v.iter().skip(2);                                    // skip first 2
v.iter().take_while(|x| **x < 4);                   // take while true
v.iter().skip_while(|x| **x < 3);                   // skip while true

// Search
v.iter().find(|x| **x == 3);                        // Option<&i32>
v.iter().position(|x| *x == 3);                     // Option<usize>
v.iter().any(|x| *x > 3);                           // bool
v.iter().all(|x| *x > 0);                           // bool

// Collect into different types
let vec: Vec<i32> = (1..=5).collect();
let set: HashSet<i32> = v.iter().copied().collect();
let map: HashMap<i32, &str> = vec![(1, "a"), (2, "b")].into_iter().collect();
let string: String = v.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", ");

// Partition into two collections
let (evens, odds): (Vec<i32>, Vec<i32>) = v.iter()
    .partition(|x| *x % 2 == 0);

// Inspect without consuming
v.iter().inspect(|x| println!("checking {}", x)).collect::<Vec<_>>();