Skip to content
Lesson 10 of 15

Step 1 of 5 · Reading · ~4 min

Learn

Collections

Vec: Growable Arrays

A Vec<T> is a list of values of one type T that can grow and shrink while the program runs. This lesson covers building one, reading from it, looping over it, and remembering the best element seen so far.

Building a Vec

Vec<i64> means "a Vec whose elements are all i64". The compiler refuses to put any other type in it.

let mut prices: Vec<i64> = Vec::new(); // empty; mut because it will grow
prices.push(250);                      // push appends to the end
prices.push(99);
println!("{} items", prices.len());    // 2 items

let days = vec![31, 28, 31];           // vec! macro: a Vec with contents
let blanks = vec![0; 4];               // [0, 0, 0, 0]: value; count

pop() removes the last element, len() counts, is_empty() asks whether there are none. A Vec owns its elements, exactly like a String owns its text: assigning it to another variable moves it (the previous lesson's rule).

Reading one element

Positions start at 0 and have type usize. days[1] is 28. Asking for a position that does not exist, such as days[3] on a three-element Vec, panics: the program stops with index out of bounds: the len is 3 but the index is 3. There is also days.get(3), which returns "nothing" instead of crashing; the Option lesson covers it.

Looping over a Vec

let days = vec![31, 28, 31];
for d in &days {
    println!("{}", d);
}

The & borrows the Vec, so days is still usable after the loop. Without it, for d in days moves the Vec into the loop and a later days.len() fails to compile. Because you borrowed, each d is a reference, &i64, not an i64. Printing works on references directly, but to copy the value into another variable, or to compare it with a plain i64, you write *d: the * follows the reference to the number it points at.

Remembering the best so far

The accumulator from the Loops lesson adds every item into a total. A tracker instead remembers one winner and replaces it whenever a better candidate arrives. What you remember can be the value itself or its position. Here the tracker keeps the position of the coldest reading, so the program can say which day it was:

let temps = vec![12, -4, 7, -9, 3];
let mut best_day = 0;               // position of the coldest so far
for i in 1..temps.len() {
    if temps[i] < temps[best_day] {
        best_day = i;
    }
}
println!("day {} was coldest at {}", best_day + 1, temps[best_day]);
// day 4 was coldest at -9

Trace: best_day starts at 0 (reading 12). i=1: -4 < 12, so best_day becomes 1. i=2: 7 < -4? no. i=3: -9 < -4, now 3. i=4: 3 < -9? no. The line is printed once, after the loop has seen everything.

Two choices keep a tracker honest. The comparison sets the goal: < keeps the smaller candidate; decide which one your goal needs. The first winner must be a real element. Seeding a value tracker with the number 0 breaks on [-3, -8, -5]: nothing beats 0 in the direction you want, so it prints 0, which is not in the list.

Reading the starter

line.split_whitespace() cuts the line into pieces. .map(|s| ...) applies a closure, a small unnamed function whose parameter is s, to each piece; here it parses the piece into a number. collect() gathers the results into the Vec. Reading a line calls unwrap() twice: once for "was there a line at all" and once for "did reading it succeed".

Common mistakes

  • Seeding with 0. For input -3 -1 -7 the output is 0 instead of -1. Start from the first element.
  • Looping over 0..v.len() - 1. The range stops one short, so for 2 7 15 the last element is never checked and you print 7.
  • Printing inside the loop. You get one line per update instead of one final answer.
  • The wrong comparison. You print the opposite end of the list.

Your exercise

Print the largest number in the line. The starter already parses it into nums: Vec<i64>; you write the tracker and print one line.

Up nextHashMapCollections

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…