Today, I explored the Vec type in Rust — a powerful and flexible way to store a list of values in memory. Vectors are dynamic arrays and are part of Rust's standard library collections. Let’s break down everything I learned.
📦 What is a Vector?
A Vector is a growable array type that stores multiple values of the same type, located contiguously in memory.
They’re great for use-cases like:
- Storing prices in a shopping cart.
- Collecting file lines.
- Managing dynamic lists.
🛠 Creating a Vector
Using Vec::new (Empty Vector with Type Annotations)
let v: Vec<i32> = Vec::new();
Since no values are inserted yet, you must specify the type.
Using vec! Macro (With Values)
let v = vec![1, 2, 3];
Rust infers the type as Vec from the initial values.
✏️ Updating a Vector
Use .push() to append elements:
let mut v = Vec::new();
v.push(5);
v.push(6);
Make sure the vector is mutable.
🔍 Reading Elements
You can read values using:
- Indexing ([]) — May Panic if index is invalid
let third = &v[2];
- .get() — Safe and returns Option
match v.get(2) {
Some(value) => println!("Third element: {}", value),
None => println!("No third element"),
}
Prefer .get() when unsure if the index exists.
⚠️ Borrowing Rules & Mutability Pitfall
Rust's borrow checker doesn’t allow mutable borrows while immutable references exist:
let mut v = vec![1, 2, 3, 4, 5];
let first = &v[0];
v.push(6); // ❌ Error: cannot borrow as mutable
println!("First element: {}", first);
The reason: pushing might reallocate the vector, invalidating the reference.
🔁 Iterating Over a Vector
Immutable Reference Loop:
let v = vec![100, 32, 57];
for i in &v {
println!("{i}");
}
Mutable Reference Loop:
let mut v = vec![100, 32, 57];
for i in &mut v {
*i += 50;
}
Use *i to access the actual value being pointed to.
🧵 Iterators and Safety
Using .iter() creates an iterator with internal borrowing. You can’t mutate the vector while iterating over it:
let mut v = vec![1, 2];
for n_ref in v.iter() {
v.push(*n_ref); // ❌ Compiler error
}
💡 To safely achieve this, use indexed access (0..v.len()), not .iter():
let v = vec![1, 2];
for i in 0..v.len() {
println!("{}", v[i]);
}
🎭 Storing Multiple Types using Enums
Vectors must store values of the same type. To store multiple types, use an enum:
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
Enums allow type-safe heterogeneous data storage with match handling.
📉 Vector Cleanup
Vectors (like any struct) are automatically dropped when they go out of scope:
{
let v = vec![1, 2, 3];
} // ✅ v is dropped here
All contents are freed along with the vector.
🧠 Summary
Here’s a recap of what I covered today about Vec:
- Vectors store values of the same type
- You can create vectors with Vec::new() or vec![]
- Use .push() to add elements
- Access via or .get() (safe Option)
- Borrowing rules prevent mutable/immutable overlap
- Iterate immutably with &v and mutably with &mut v
- Iterators and mutation must be handled carefully
- Use enum for multi-type collections
- Vectors clean up automatically on scope exit
Tomorrow, I’ll dive into another standard collection: String. Stay tuned! 🧵
Top comments (0)