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<_>>();