Step 6 of 6
A first look at Vec: a list that grows
An array's length is fixed when you write the program. Often you don't know it in advance: orders arrive, players join, a file has however many lines it has. For that, Rust has Vec<T>, called a vector: a list of values of one type that can grow and shrink while the program runs. It's the collection you'll use most in Rust. Module 16 covers it in depth; here are the basics.
fn main() {
let mut queue = vec![101, 102];
queue.push(103);
queue.push(104);
println!("{:?}", queue);
println!("{} tickets, first is {}", queue.len(), queue[0]);
}
[101, 102, 103, 104]
4 tickets, first is 101
vec![...]is a macro (note the!) that creates a vector holding those values. It looks like an array withvec!in front..push(value)adds a value at the end. Pushing changes the vector, so it must belet mut.- Indexing,
.len()and{:?}work just like with arrays, and an out-of-bounds index panics the same way. - The type is written
Vec<i32>: the angle brackets hold the element type.
Starting empty
Vec::new() creates an empty vector, ready to be filled in a loop:
fn main() {
let mut squares = Vec::new();
for n in 1..=5 {
squares.push(n * n);
}
println!("{:?}", squares);
}
[1, 4, 9, 16, 25]
Rust works out the element type from what you push. If you never push anything, it can't tell, and asks you (error E0282, type annotations needed for `Vec<_>` ). Then write the type: let scores: Vec<i32> = Vec::new();
Array or Vec?
Array [T; N] |
Vector Vec<T> |
|
|---|---|---|
| Length | fixed, part of the type | changes at run time |
| Typical use | days of the week, a 3×3 board | orders, lines of input, search results |
| Adding elements | impossible | push |
Under the hood, a vector keeps its elements in a block of memory it can grow (on the heap, which module 09 explains), while an array is stored directly where it's declared.
Looping over a vector
You can loop over the indexes, for i in 0..v.len(), exactly as with arrays. In real code you'll more often see this form:
fn main() {
let lap_times = vec![62, 58, 60];
let mut total = 0;
for t in &lap_times {
total += t;
}
println!("{} laps, total {} s", lap_times.len(), total);
}
3 laps, total 180 s
The & in &lap_times lets the loop look at the elements without using up the vector. Without it, for t in lap_times takes the vector over, and using lap_times after the loop is an error (E0382, borrow of moved value: `lap_times` ). Why that happens is the topic of the next phase: ownership (module 09) and borrowing with & (module 10). For now, loop over &v (or over the indexes) when you still need v afterwards.
Common mistakes
- Forgetting
mut:v.push(3)on a non-mutvector gives error E0596,cannot borrow `v` as mutable, as it is not declared as mutable. - Pushing the wrong type: a
Vecof integers can't take"three"(expected integer, found &str). Every element has the same type. - Confusing arrays and vectors in types:
[i32; 3]is an array,Vec<i32>a vector.vec![1, 2, 3]makes a vector,[1, 2, 3]an array.
Your task
Start from an empty vector and use a loop with push to collect the multiples of 7 from 7 up to 49. Then print the vector and how many numbers it holds:
[7, 14, 21, 28, 35, 42, 49]
count: 7
Challenge 2
Fill the blanks: create an empty cart, add a price to it, and print how many items it holds. The program should print 2 items: [499, 1250].
Challenge 3
Write evens_up_to(n), which returns a vector of the even numbers from 2 up to and including n. For example evens_up_to(10) returns [2, 4, 6, 8, 10], and evens_up_to(1) returns an empty vector.