tezvyn:

Rust Vectors: Your Go-To Growable List

AI-drafted, machine-checkedSource: doc.rust-lang.orgbeginner

A `Vec<T>` is Rust's smart, growable array. It automatically gets more memory when full, keeping items together for fast access. Use it for lists of unknown size. The footgun: frequent reallocations can be slow if you don't pre-allocate capacity.

WHY IT EXISTS Fixed-size arrays are inflexible, and other dynamic structures like linked lists have slow element access. Rust's Vec<T> was created to provide the best of both worlds: a list that can grow on-demand while maintaining the fast O(1) indexed access of a contiguous array.

THE MENTAL MODEL A Vec<T> is a manager for a contiguous block of memory on the heap. It tracks three things: a pointer to the memory, its length (how many items are actually in it), and its capacity (how many items the allocated memory block can hold). When you try to add an item and length equals capacity, the vector is full. It must then find a new, larger block of memory, copy all the old elements over, and finally add the new element.

HOW IT WORKS You create a vector with Vec::new() or the vec![] macro. As you push items, the vector's length increases. If a push would make the length exceed the capacity, the vector reallocates, typically doubling its capacity. This strategy, called amortization, makes the average cost of a push cheap, even though individual pushes can sometimes be slow. Because the elements are stored side-by-side in memory, accessing an element by its index (e.g., my_vec[2]) is extremely fast.

WHEN TO USE IT A Vec<T> is the default, go-to collection for a sequence of items of the same type. Use it when you're collecting results from an iterator, buffering data from a file or network, or managing a list of objects where you don't know the final count ahead of time. If you can estimate the final size, use Vec::with_capacity(n) to pre-allocate the memory and avoid reallocations entirely.

WHEN NOT TO USE IT Avoid Vec<T> if you frequently need to add or remove elements from the beginning or middle of the list. Each such operation requires shifting all subsequent elements, which is an O(n) operation and can be very slow for large vectors. For this use case, a VecDeque (double-ended queue) is a much better fit. If an item's size is known at compile time and never changes, a stack-allocated array [T; N] is more performant.

ONE CANONICAL EXAMPLE Visualizing capacity and length is key. let mut numbers = Vec::with_capacity(2); creates a vector with length 0 and capacity 2. After numbers.push(10); and numbers.push(20);, its length is 2 and it's full. The next call, numbers.push(30);, triggers a reallocation. The vector allocates new memory (e.g., for capacity 4), copies [10, 20] to the new location, and then pushes 30. The length is now 3.

Read the original → doc.rust-lang.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.