Back to Blog

September 28, 2025

Vectors: Expandable Warehouse Aisles

While arrays are rigid shelves built to a fixed size, vectors (Vec<T>) are flexible aisles with adjustable shelving. As new boxes (elements) arrive, the aisle can expand, sometimes requiring a forklift to relocate all existing boxes into a bigger space when the aisle overflows.

  • Organization: All boxes in a vector are stored together in sequence on the heap.
  • Dynamic Growth: The aisle can extend to fit new inventory as needed.
  • Efficient Access: Finding a box by its index is direct, just like with arrays.

Rust Vectors: Code and Memory Layout

Declaring and using a vector in Rust usually looks like this:

fn main() {
    let mut aisle: Vec<i32> = vec![100, 101, 102];
    aisle.push(103);
    aisle.push(104);
    println!("Box 2 contains: {}", aisle[^2]);
}

Memory Layout Details

Vectors are managed using a control block on the stack—a structure containing:

  • A pointer to the start of the aisle on the heap.
  • The current length (number of boxes used).
  • The total capacity (max boxes before reallocation).

The actual inventory (data) is contiguous—boxes lined up in sequence—allocated on the heap, not the stack like arrays.^4^1

When the aisle reaches its maximum length (capacity), Rust allocates a larger space elsewhere in the warehouse, moves every box, and updates its labels—a process called reallocation.


Diagram: Vector as Expandable Aisle

graph LR
    ControlBlock["Control Block<br>Stack"]
    HeapAisle0["Box 0<br>100"]
    HeapAisle1["Box 1<br>101"]
    HeapAisle2["Box 2<br>102"]
    HeapAisle3["Box 3<br>103"]
    HeapAisle4["Box 4<br>104"]
    Capacity["Capacity<br>6"]
    ControlBlock -- pointer, len, cap --> HeapAisle0
    HeapAisle0 --> HeapAisle1 --> HeapAisle2 --> HeapAisle3 --> HeapAisle4
    HeapAisle4 -.-> Capacity

This diagram shows the vector's stack-based control block pointing to the start of the heap-allocated aisle, with boxes packed in order. Capacity can exceed length—unused space may be present, ready for future boxes.


How Vectors Grow: Warehouse Relocation

When the vector's length reaches its capacity, Rust:

  • Allocates a larger memory block in the heap (a bigger aisle).
  • Copies all current boxes into the new location.
  • Updates the control block to reference the new block.

This is like expanding warehouse shelving: when demand grows, everything is moved to a longer aisle to maintain the sequence.


Key Properties and Use Cases

  • Random Access: Fetching a box by index is instant.
  • Flexible Growth: Ideal for scenarios where inventory size is unpredictable.^3
  • Cache Locality: Still fairly cache friendly, since boxes are contiguous, boosting iteration speed.
  • Reallocation Cost: Growing the aisle sometimes requires a costly move of all boxes.

Use when:

  • The number of items can change, or isn't known at compile time.
  • You need stack efficiency for control, but dynamic, heap-based storage for actual data.^3

Rust Patterns: Iteration and Slicing

Efficient iteration leverages contiguous layout:

let aisle = vec![1, 2, 3, 4, 5];
for box_item in aisle.iter() {
    println!("{}", box_item);
}

Slicing lets you inspect sections of the aisle in one pass.


Vectors in Rust embody the spirit of expandable, efficient warehouse aisles. Their memory model and growth logic power dynamic collections, offering engineers the best of both structured access and runtime flexibility.^1 ^10^12^14^16^18^20^6^8