Skip to content
Vec: Growable Arrays
step 1/5

Reading — step 1 of 5

Learn

~2 min readCollections

Vec: Growable Arrays

Vec<T> is Rust's growable array — the default collection, the one you reach for first, and (not coincidentally) your first daily-driver generic type: Vec<i32> holds i32s, Vec<String> holds Strings, and the <T> machinery guarantees at compile time that you never fish a String out of a Vec of numbers.

Creating and growing

let mut nums: Vec<i64> = Vec::new();   // empty — needs mut to grow
nums.push(10);
nums.push(20);

let nums = vec![10, 20, 30];           // the vec! macro: literal + contents
let zeros = vec![0; 5];                // [0, 0, 0, 0, 0] — value; count

push appends, pop removes and returns the last element, len() counts, .is_empty() asks. A Vec owns its elements (heap-allocated, freed when the Vec drops) — it's the String of collections, and &[T] (a slice) is its &str: functions that only need to read should take &[i64], and a &Vec<i64> coerces to it automatically.

Reading: two doors, different failure modes

let v = vec![1, 2, 3];

v[1]          // 2 — direct indexing. Out of bounds? PANIC, immediately.
v.get(1)      // Some(&2) — and v.get(99) is None: no panic, you decide.

This pair is a Rust design signature you'll see everywhere: the convenient door that crashes loudly on misuse, and the careful door that returns an Option and makes you handle absence. Grader input with promised bounds → index freely. Anything user-shaped → get. (Contrast with C, where out-of-bounds reads don't crash — they hand you garbage and a security advisory. Rust's panic is the good outcome.)

Iterating

for n in &v {              // borrow the elements — the everyday form
    println!("{n}");
}
for n in &mut v_mut {      // borrow mutably to modify in place
    *n *= 2;               // * follows the reference — chapter 4 formalizes this
}

That & is doing real work: for n in v (no &) consumes the Vec — it's gone afterward. Until the ownership chapter explains why, the habit is: iterate with &, and the compiler will tell you on the rare day you want otherwise.

Your exercise: Largest Number

Read numbers, print the largest — the tracker pattern, sibling of the accumulator:

let mut best = i64::MIN;          // start at the floor
for n in numbers {
    if n > best {
        best = n;
    }
}
println!("{best}");

Two classic bugs to dodge: initialize with i64::MIN (or the first element) — starting at 0 breaks on all-negative input, the test case that exists precisely to catch it; and compare with > per the spec (with >= ties keep the last max — indistinguishable for values, wrong the moment an exercise asks for the index).

Worth knowing after you've written the loop by hand: Rust's iterators can do this in one line — numbers.iter().max() (it returns an Option, empty input being a real case). Write the manual version for this exercise; the Iterators lesson makes the one-liners honest.

Discussion

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

Sign in to post a comment or reply.

Loading…