Rust Vectors Collections
A vector is a list that can grow and shrink as your program runs. It stores multiple values of the same type in order. Vectors are the most commonly used collection in Rust.
Creating a Vector
fn main() {
let mut scores: Vec<i32> = Vec::new();
scores.push(10);
scores.push(20);
scores.push(30);
println!("{:?}", scores);
}
Output:
[10, 20, 30]
The vec! Macro
Use the vec! macro to create a vector with values already inside:
let scores = vec![10, 20, 30];
Rust infers the type from the values. This is the most common way to create vectors with initial data.
The Expandable Shelf Diagram
Array (fixed): [ 10 | 20 | 30 ] ← Cannot add more items Vector (dynamic): [ 10 | 20 | 30 | __ | __ ] ← Grows as needed
Adding and Removing Elements
let mut numbers = vec![1, 2, 3];
numbers.push(4); ← Add to the end: [1, 2, 3, 4]
numbers.push(5); ← [1, 2, 3, 4, 5]
let last = numbers.pop(); ← Remove from end → Some(5)
← Vector is now [1, 2, 3, 4]
pop() returns an Option<T> because the vector might be empty when you call it.
Accessing Elements
Two ways to read a value at a specific position:
let v = vec![10, 20, 30, 40, 50]; let third = v[2]; ← Direct access: 30 (panics if out of bounds) let maybe = v.get(2); ← Safe access: Some(30) or None
When to Use Which
v[i] ← Use when the index must exist. Program panics if not. v.get(i) ← Use when the index might not exist. Returns Option.
match v.get(10) {
Some(val) => println!("Value: {}", val),
None => println!("Index out of range"),
}
Iterating Over a Vector
Loop through every element with a for loop:
let temperatures = vec![22.0, 25.5, 19.0, 30.1];
for temp in &temperatures {
println!("{} degrees", temp);
}
Output:
22 degrees 25.5 degrees 19 degrees 30.1 degrees
Use &temperatures to borrow the vector. Without the ampersand, the loop would move ownership and you could not use the vector afterward.
Modify While Iterating
let mut prices = vec![100, 200, 300];
for price in &mut prices {
*price += 10; ← Dereference with * to change the actual value
}
println!("{:?}", prices); ← [110, 210, 310]
Vector Length and Capacity
let v = vec![1, 2, 3, 4, 5];
println!("Length: {}", v.len()); ← 5 (number of items)
println!("Is empty: {}", v.is_empty()); ← false
Storing Different Types with Enums
Vectors can only hold one type. When you need to store values of different types, wrap them in an enum:
enum Cell {
Integer(i32),
Float(f64),
Text(String),
}
let row = vec![
Cell::Integer(42),
Cell::Float(3.14),
Cell::Text(String::from("hello")),
];
The Mixed Bag Diagram
Row: [ Integer(42) | Float(3.14) | Text("hello") ]
↑ ↑ ↑
All are of type Cell — the vector is homogeneous (same type)
but each Cell variant carries different data
Common Vector Operations
v.push(x) ← Add x to the end v.pop() ← Remove and return last element (Option) v.len() ← Number of elements v.is_empty() ← True if len() == 0 v[i] ← Get element at index i (panics if out of bounds) v.get(i) ← Get element as Option (safe) v.contains(&x) ← True if x is in the vector v.sort() ← Sort in ascending order v.reverse() ← Reverse the order v.clear() ← Remove all elements
Vector Memory Model
let v = vec![1, 2, 3];
Stack: [ pointer | length=3 | capacity=3 ]
↓
Heap: [ 1 | 2 | 3 ]
When capacity runs out during push, Rust allocates a larger block
on the heap and copies all elements there automatically.
This growth happens automatically. You never manage the heap memory yourself.
Quick Reference
Vec::new() ← Empty vector vec![1, 2, 3] ← Vector with values v.push(x) ← Add to end v.pop() ← Remove from end v[i] ← Access by index (unsafe) v.get(i) ← Access by index (safe, returns Option) for x in &v ← Iterate (borrowing)
