Skip to main content
A Vec<T> (vector) is a Sized, contiguous, and dynamically growable array type that manages a heap-allocated buffer. It provides O(1)O(1) indexing, amortized O(1)O(1) push operations, and guarantees that its elements are stored sequentially in memory, making it highly cache-friendly.

Memory Layout

Under the hood, a Vec<T> is represented as a struct containing exactly three machine words:
  1. Pointer: A non-null pointer (internally represented as Unique<T>, which wraps NonNull<T>) to the start of the allocated heap buffer. This strict non-null guarantee enables Rust’s null-pointer optimization, allowing types like Option<Vec<T>> to have the exact same memory footprint as Vec<T>.
  2. Capacity: A usize representing the total number of elements the buffer can currently hold without triggering a reallocation.
  3. Length: A usize representing the number of initialized elements currently in the vector. The invariant len <= capacity is always maintained.

Initialization Syntax

Vectors can be initialized empty, pre-allocated, or populated via macros.

Growth and Reallocation Mechanics

When an element is added to a Vec<T> and len == capacity, the vector must grow. The standard library handles this by:
  1. Allocating a new, larger heap buffer (historically doubling the capacity).
  2. Moving the existing elements from the old buffer to the new buffer.
  3. Deallocating the old buffer.
Because reallocation is an O(n)O(n) operation, pushing to a vector is an amortized O(1)O(1) operation. Using Vec::with_capacity bypasses this overhead by satisfying the capacity requirement at instantiation.

Ownership and Memory Management

Vec<T> owns its elements. When a vector goes out of scope, its Drop implementation is triggered. This sequentially calls the Drop trait on all initialized elements (from index 0 to len - 1) and subsequently frees the underlying heap buffer.

Slicing and Deref Coercion

Vec<T> implements both Deref<Target = [T]> and DerefMut. This means a vector automatically coerces to an immutable slice (&[T]) via Deref, or a mutable slice (&mut [T]) via DerefMut, when passed by reference. Slices provide a view into the vector’s contiguous memory without taking ownership.

Access Patterns

Accessing elements requires navigating Rust’s borrowing rules and bounds checking.

Iteration Mechanics

Vectors support three primary modes of iteration, directly mapping to Rust’s ownership semantics:
Tired of Poor Rust Skills? Fix That With Deep Grasping!Learn More