Rust Cheatsheet

Collections

Use this Rust reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Vec\<T\> — Dynamic Array

The most commonly used collection. Heap-allocated, growable.

// Creation
let v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3, 4, 5];
let v = Vec::with_capacity(100);      // pre-allocate
let v: Vec<i32> = (0..5).collect();  // from iterator
let v = vec![0; 10];                  // [0, 0, ..., 0] — 10 zeros

// Push / pop
let mut v = vec![1, 2, 3];
v.push(4);           // append to end
v.pop();             // remove and return last: Option<T>
v.insert(1, 10);     // insert at index 1: [1, 10, 2, 3]
v.remove(1);         // remove at index 1, return element (shifts elements)
v.swap_remove(1);    // fast remove (swaps with last, no shift)
v.clear();
v.truncate(2);       // keep first 2 elements

// Access
v[0]                 // panics if out of bounds
v.get(0)             // Option<&T>
v.get_mut(0)         // Option<&mut T>
v.first()            // Option<&T>
v.last()             // Option<&T>
v.first_mut()        // Option<&mut T>
v.last_mut()         // Option<&mut T>

// Info
v.len()
v.is_empty()
v.capacity()
v.spare_capacity_mut()  // uninitialized spare capacity

// Memory
v.reserve(10)            // ensure additional capacity for 10
v.reserve_exact(10)
v.shrink_to_fit()
v.shrink_to(5)

// Mutation
v.sort();                             // in-place sort (must be Ord)
v.sort_by(|a, b| a.cmp(b));
v.sort_by_key(|x| x.abs());
v.sort_unstable();                    // faster, not stable
v.sort_unstable_by(|a, b| b.cmp(a)); // reverse sort
v.sort_unstable_by_key(|x| x.len());
v.reverse();
v.dedup();                            // remove consecutive duplicates
v.dedup_by(|a, b| a == b);
v.dedup_by_key(|x| x.to_lowercase());
v.retain(|&x| x > 0);               // keep only matching
v.retain_mut(|x| { *x *= 2; *x < 100 });
v.extend([4, 5, 6]);
v.extend_from_slice(&[7, 8]);
v.append(&mut other);                 // drains other into self

// Search
v.contains(&3)
v.starts_with(&[1, 2])
v.ends_with(&[4, 5])
v.binary_search(&3)               // Result<usize, usize> — must be sorted
v.binary_search_by(|x| x.cmp(&3))
v.binary_search_by_key(&3, |x| x.abs())
v.iter().position(|&x| x == 3)   // Option<usize> — linear
v.iter().rposition(|&x| x == 3)  // last position

// Slices / windows / chunks
v.as_slice()
v.split_at(2)                // (&[T], &[T]) at index
v.split_at_mut(2)
v.windows(3)                 // overlapping windows of size 3
v.chunks(3)                  // non-overlapping chunks of size 3
v.chunks_exact(3)            // exact chunks (no remainder)
v.rchunks(3)                 // chunks from the right
v.split(|&x| x == 0)        // split on predicate
v.splitn(3, |&x| x == 0)    // at most 3 parts

// Drain (remove and iterate a range)
let drained: Vec<_> = v.drain(1..3).collect();

// Splice (replace a range with an iterator)
v.splice(1..3, [10, 20, 30]);

// Flatten / concat
let nested = vec![vec![1, 2], vec![3, 4]];
let flat: Vec<i32> = nested.into_iter().flatten().collect();
let flat: Vec<i32> = [&[1, 2][..], &[3, 4]].concat();

VecDeque\<T\> — Double-Ended Queue

use std::collections::VecDeque;

let mut dq: VecDeque<i32> = VecDeque::new();
let mut dq: VecDeque<i32> = VecDeque::with_capacity(10);
let mut dq: VecDeque<i32> = vec![1, 2, 3].into();  // from Vec

// Front
dq.push_front(0);
dq.pop_front();          // Option<T>
dq.front()              // Option<&T>
dq.front_mut()          // Option<&mut T>

// Back
dq.push_back(4);
dq.pop_back();           // Option<T>
dq.back()               // Option<&T>
dq.back_mut()           // Option<&mut T>

// Index
dq[0]
dq.get(0)               // Option<&T>

// Rotate
dq.rotate_left(2);
dq.rotate_right(1);

// Convert
let v: Vec<i32> = dq.into_iter().collect();
let contiguous = dq.make_contiguous(); // &mut [T], ensures contiguous memory

LinkedList\<T\> — Doubly Linked List

Rarely needed; prefer Vec or VecDeque. Useful for O(1) split/append.

use std::collections::LinkedList;

let mut list: LinkedList<i32> = LinkedList::new();
list.push_front(1);
list.push_back(2);
list.push_back(3);
list.pop_front()   // Some(1)
list.pop_back()    // Some(3)
list.front()       // Option<&T>
list.back()        // Option<&T>
list.len()
list.is_empty()
list.contains(&2)
list.append(&mut other);   // O(1) — drains other
list.split_off(1)          // split at index

HashMap\<K, V\>

use std::collections::HashMap;

// Creation
let mut map: HashMap<String, i32> = HashMap::new();
let map = HashMap::with_capacity(100);
let map: HashMap<&str, i32> = [("a", 1), ("b", 2)].into_iter().collect();
// or from arrays of tuples:
let map: HashMap<_, _> = [("one", 1), ("two", 2)].into();

// Insert / remove
map.insert("alice".to_string(), 42);
map.remove("alice")          // Option<V>
map.remove_entry("alice")    // Option<(K, V)>

// Access
map.get("alice")             // Option<&V>
map.get_mut("alice")         // Option<&mut V>
map["alice"]                 // panics if missing
map.contains_key("alice")
map.len()
map.is_empty()

// Entry API (insert-if-absent / update)
map.entry("alice".to_string()).or_insert(0);             // insert 0 if absent
map.entry("alice".to_string()).or_insert_with(|| compute_value());
map.entry("alice".to_string()).or_default();             // insert V::default()
*map.entry("counter".to_string()).or_insert(0) += 1;    // increment counter

// Modify existing entry
map.entry("alice".to_string()).and_modify(|v| *v += 10).or_insert(0);

// Iteration
for (k, v) in &map { println!("{}: {}", k, v); }
for k in map.keys() {}
for v in map.values() {}
for v in map.values_mut() { *v += 1; }
map.iter()
map.iter_mut()
map.into_iter()   // consumes map, yields (K, V)

// Retain
map.retain(|k, v| v > &0);

// Extend
map.extend([("c".to_string(), 3), ("d".to_string(), 4)]);

// Drain
for (k, v) in map.drain() {}

Word count example:

let text = "hello world hello rust world hello";
let mut counts: HashMap<&str, u32> = HashMap::new();
for word in text.split_whitespace() {
    *counts.entry(word).or_insert(0) += 1;
}
// {"hello": 3, "world": 2, "rust": 1}

BTreeMap\<K, V\> — Sorted Map

Like HashMap but keys are always sorted. Iteration is in key order.

use std::collections::BTreeMap;

let mut map = BTreeMap::new();
map.insert(3, "c");
map.insert(1, "a");
map.insert(2, "b");

for (k, v) in &map { print!("{}: {} ", k, v); }  // 1: a 2: b 3: c

// Range queries (unique to BTreeMap)
for (k, v) in map.range(1..=2) {}
for (k, v) in map.range(..2) {}     // all keys < 2
for (k, v) in map.range(2..) {}     // all keys >= 2

// First/last key
map.first_key_value()    // Option<(&K, &V)>
map.last_key_value()     // Option<(&K, &V)>
map.pop_first()          // Option<(K, V)>
map.pop_last()           // Option<(K, V)>

// Entry API works the same as HashMap

HashSet\<T\>

use std::collections::HashSet;

// Creation
let mut set: HashSet<i32> = HashSet::new();
let set: HashSet<i32> = vec![1, 2, 3].into_iter().collect();
let set: HashSet<_> = [1, 2, 3, 2, 1].into_iter().collect(); // dedupes

// Mutation
set.insert(4);     // returns bool (true if new)
set.remove(&4);    // returns bool (true if was present)
set.take(&4)       // removes and returns Option<T>
set.replace(4)     // replaces and returns Option<old>

// Query
set.contains(&2)
set.len()
set.is_empty()

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

let union: HashSet<_> = a.union(&b).collect();              // {1,2,3,4,5,6}
let inter: HashSet<_> = a.intersection(&b).collect();       // {3,4}
let diff_a: HashSet<_> = a.difference(&b).collect();        // {1,2} (in a, not b)
let diff_b: HashSet<_> = b.difference(&a).collect();        // {5,6}
let sym: HashSet<_> = a.symmetric_difference(&b).collect(); // {1,2,5,6}

// Relationships
a.is_subset(&b)     // false
a.is_superset(&b)   // false
a.is_disjoint(&b)   // false

// Retain
set.retain(|&x| x % 2 == 0);  // keep only even

BTreeSet\<T\> — Sorted Set

use std::collections::BTreeSet;

let mut set = BTreeSet::new();
set.insert(3); set.insert(1); set.insert(2);

// Iteration in sorted order
for x in &set { print!("{} ", x); }  // 1 2 3

// Range queries
for x in set.range(1..=2) {}
set.first()    // Option<&T>
set.last()     // Option<&T>
set.pop_first()  // Option<T>
set.pop_last()   // Option<T>

// Set operations (same as HashSet)
a.union(&b).collect::<BTreeSet<_>>()
a.intersection(&b).collect::<BTreeSet<_>>()

BinaryHeap\<T\> — Priority Queue

Max-heap by default (largest element first).

use std::collections::BinaryHeap;
use std::cmp::Reverse;

// Max-heap
let mut heap = BinaryHeap::new();
heap.push(3);
heap.push(1);
heap.push(4);
heap.push(1);
heap.push(5);

heap.peek()     // Some(&5) — view max without removing
heap.pop()      // Some(5) — remove max
heap.len()
heap.is_empty()
heap.push(2);

// Drain in sorted order (descending)
while let Some(top) = heap.pop() {
    print!("{} ", top);   // 5 4 3 2 1 1
}

// Min-heap using Reverse
let mut min_heap: BinaryHeap<Reverse<i32>> = BinaryHeap::new();
min_heap.push(Reverse(3));
min_heap.push(Reverse(1));
min_heap.push(Reverse(5));
let Reverse(min) = min_heap.pop().unwrap();  // 1

// Build from Vec
let heap: BinaryHeap<i32> = vec![3, 1, 4, 1, 5].into();

// Convert
let sorted: Vec<i32> = heap.into_sorted_vec();  // ascending order

Iterator Methods — Full Reference

All collections implement IntoIterator; all these methods work on any iterator:

Creating Iterators

MethodReturnsDescription
iter()&Tborrow
iter_mut()&mut Tmutable borrow
into_iter()Tconsuming
(0..n)i32srange iterator
std::iter::once(x)Tsingle item
std::iter::repeat(x)Tinfinite
std::iter::empty()Tempty
std::iter::successors(init, f)Tunfold from previous
std::iter::from_fn(f)Tclosure-based

Lazy Adapters

AdapterDescription
.map(f)transform each item
.filter(pred)keep matching items
.filter_map(f)map + filter: f returns Option
.flat_map(f)map then flatten one level
.flatten()flatten nested iterables
.take(n)first n items
.take_while(pred)take until predicate is false
.skip(n)skip first n items
.skip_while(pred)skip until predicate is false
.enumerate()add index: (usize, T)
.zip(iter)pair items: (A, B)
.chain(iter)concatenate two iterators
.rev()reverse (requires DoubleEndedIterator)
.peekable()add .peek() method
.cloned()&T → T via Clone
.copied()&T → T via Copy
.step_by(n)take every nth item
.cycle()repeat infinitely
.inspect(f)side-effect for debugging
.scan(state, f)like fold but yields each step
.windows(n)overlapping windows (slice-only)
.chunks(n)non-overlapping chunks (slice-only)

Consuming (Terminal) Operations

MethodReturnsDescription
.collect::<C>()collectionany FromIterator type
.count()usizenumber of items
.sum()S: Sumsum of items
.product()P: Productproduct of items
.min()Option<T>minimum
.max()Option<T>maximum
.min_by(f)Option<T>min with comparator
.max_by(f)Option<T>max with comparator
.min_by_key(f)Option<T>min by key function
.max_by_key(f)Option<T>max by key function
.find(pred)Option<T>first matching item
.find_map(f)Option<B>first non-None from f
.position(pred)Option<usize>index of first match
.rposition(pred)Option<usize>index of last match
.any(pred)booltrue if any match
.all(pred)booltrue if all match
.fold(init, f)Baccumulate
.reduce(f)Option<T>fold without initial
.for_each(f)()consume for side effects
.last()Option<T>last item
.nth(n)Option<T>nth item (0-indexed)
.unzip()(A, B)split (A,B) pairs into two vecs
.partition(pred)(C, C)split into matching and not
// Practical examples
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

let sum: i32 = v.iter().filter(|&&x| x % 2 == 0).sum();       // 30
let evens: Vec<i32> = v.iter().copied().filter(|x| x % 2 == 0).collect();
let squares: Vec<i32> = v.iter().map(|&x| x * x).collect();
let first_gt5: Option<&i32> = v.iter().find(|&&x| x > 5);     // Some(&6)
let any_neg = v.iter().any(|&x| x < 0);                        // false
let total: i32 = v.iter().copied().fold(0, |acc, x| acc + x); // 55

// Chained pipeline
let result: Vec<String> = (1..=5)
    .filter(|x| x % 2 != 0)
    .map(|x| x * x)
    .map(|x| format!("{}^2", x))
    .collect();
// ["1^2", "9^2", "25^2"]  — wait, "1^2","9^2","25^2"

// Group by (manual with HashMap)
let words = vec!["apple", "banana", "avocado", "blueberry", "cherry"];
let mut by_first_char: HashMap<char, Vec<&str>> = HashMap::new();
for word in &words {
    by_first_char.entry(word.chars().next().unwrap())
        .or_default()
        .push(word);
}

Choosing the Right Collection

Use caseRecommended
Ordered list, fast append/popVec<T>
Queue / dequeVecDeque<T>
StackVec<T> (push/pop)
Priority queueBinaryHeap<T>
Key-value, fast lookupHashMap<K,V>
Key-value, sorted keysBTreeMap<K,V>
Unique items, fast lookupHashSet<T>
Unique items, sortedBTreeSet<T>
Linked list (rarely needed)LinkedList<T>