DEV Community

Subesh Yadav
Subesh Yadav

Posted on

🧠 Day 12 of #100DaysOfRust — Deep Dive into Vectors in Rust

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();
Enter fullscreen mode Exit fullscreen mode

Since no values are inserted yet, you must specify the type.

Using vec! Macro (With Values)

let v = vec![1, 2, 3];
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

Make sure the vector is mutable.

🔍 Reading Elements

You can read values using:

  1. Indexing ([]) — May Panic if index is invalid
let third = &v[2];
Enter fullscreen mode Exit fullscreen mode
  1. .get() — Safe and returns Option
match v.get(2) {
    Some(value) => println!("Third element: {}", value),
    None => println!("No third element"),
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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}");
}
Enter fullscreen mode Exit fullscreen mode

Mutable Reference Loop:

let mut v = vec![100, 32, 57];
for i in &mut v {
    *i += 50;
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

💡 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]);
}
Enter fullscreen mode Exit fullscreen mode

🎭 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),
];
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)