Why Vec exists
A static array has a length fixed at compile time: [i32; 4] always holds four integers. That is a problem when the number of items depends on the data, such as lines read from input or results collected in a loop. Rust's answer is Vec<T>, usually called a vector. It is a dynamic array: a sequence of values of one type T whose length can change while the program runs. A vector stores its elements in one contiguous block on the heap and takes care of growing that block when needed.
Use an array when the size is known and constant, and a Vec in nearly every other case. Vectors are by far the most common collection in everyday Rust code.
Creating a Vec
An empty vector
Write the type with the element type in angle brackets and call Vec::new():
let mut sandwich: Vec<String> = Vec::new();
This creates an empty vector whose items are Strings. The annotation is needed here because nothing yet tells Rust what the elements will be. Rust can also infer the type from later code, such as a first push. The mut keyword is needed to add or remove items afterwards, because bindings are immutable by default.
With initial values: the vec! macro
The vec! macro builds a vector from a list, like an array literal:
let sandwich: Vec<&str> = vec!["peanut butter", "jelly", "bread"];
The type is written out only for illustration. Rust infers it from the items, so let sandwich = vec!["peanut butter", "jelly", "bread"]; means the same. String literals have type &str, hence Vec<&str>.
Repeating a value
Like an array, a vector can be filled with one value repeated:
let animals: Vec<&str> = vec!["cat"; 5];
This is five copies of "cat". Unlike the array form [value; N], the count can be a variable computed at run time, as in vec![0; n].
Working with a vector
A vector knows its size, and a few methods cover the first things you'll do with it:
len()returns the number of items, as ausize.push(x)adds an item at the end.pop()removes the last item and returns it wrapped in anOption:Some(x), orNoneif the vector was empty.
For a vector declared with let mut w: Vec<i32> = Vec::new();, after w.push(1); and w.push(2); the contents are [1, 2] and len() is 2. Then w.pop() returns Some(2) and leaves [1]. To print a vector, use the debug placeholder: println!("{:?}", w).
The vector owns its items. Assigning it to another variable moves ownership, and clone() makes a separate copy.
The lesson's exercise
The exercise declares two vectors with the vec! macro.
fruitsholds the string literals"mango","kiwi"and"grapefruit". Its type isVec<&str>.agesholds the integers14,32,50and21. Integer literals default toi32, so its type isVec<i32>.
let fruits = vec!["mango", "kiwi", "grapefruit"];
let ages = vec![14, 32, 50, 21];
Neither binding uses mut, because the exercise only creates the vectors. To push or remove items later, you would declare them with let mut.
Common mistakes
- Forgetting
mut. Callingpushon a binding declared withoutmutis a compile error. Addmutto the declaration. - Leaving out the
!.vec[...]isn't valid. The macro isvec!, with the exclamation mark. - Mixing element types.
vec![1, "two"]doesn't compile, because all elements must have the same type. - An empty vector with no type.
let v = Vec::new();with no later use that fixes the type produces a "type annotations needed" error. Annotate it, as inVec<String>above. - Square brackets for the type. The element type goes in angle brackets:
Vec<i32>, notVec[i32]. - Mixing up
[x; n]andvec![x; n]. The first is a fixed array, the second a vector.
Key takeaways
Vec<T>is a growable array of one element type.- Create one with
Vec::new(), or withvec![...]andvec![value; count]. - Declare it with
let mutif you plan to change it. - Use
len(),pushandpopfor the basics, and{:?}to print it.
