Skip to content

Intermediate · Error handling and collections · topic 25 of 50 · 25 min

Vec<T>: growable lists

Explanation

Vec<T> is a growable list of values of one type, stored on the heap. Create one with Vec::new() or vec![...], add with push, remove with pop, and read with v[i] (panics if out of range) or v.get(i) (returns an Option). Loop with for x in &v to read and for x in &mut v to change, and remember you cannot push while holding a reference into the Vec.

Why Vec?

Arrays have a fixed length. Real data rarely does: orders arrive, users sign up, lines are read from a file. Vec<T> (vector) is Rust's growable list. T is the type of the items; Vec<u32> holds u32 values, Vec<String> holds Strings. All items have the same type.

rust
let mut orders: Vec<u32> = Vec::new();   // empty, type written
orders.push(101);
orders.push(102);

let cities = vec!["Delhi", "Pune", "Kochi"];  // vec! macro with items
let zeros = vec![0; 5];                      // [0, 0, 0, 0, 0]
println!("{:?} {:?} {}", orders, cities, zeros.len());
Prints: [101, 102] ["Delhi", "Pune", "Kochi"] 5

How a Vec looks in memory

output
orders (stack)            heap buffer (capacity 4)
  ptr  ------------->  [101][102][ free ][ free ]
  len      = 2
  capacity = 4
Like String, a Vec has pointer, length and capacity. When it is full, push allocates a bigger buffer and moves the items.

If you know roughly how many items you will add, Vec::with_capacity(n) reserves space once and avoids repeated reallocations.

Think of it like this: A Vec is like booking a table at a restaurant for a group that keeps growing. The restaurant gives you a table for four (the capacity). While you are four or fewer, people just sit down (push is instant). When the fifth friend arrives, the whole group moves to a bigger table, usually about twice the size, carrying their plates along. Moving takes a moment, but it happens rarely, so on average adding a person is still quick.

Because the Vec owns its items, dropping the Vec drops every item inside it too. A Vec<String> frees all its Strings and then its own buffer when it goes out of scope, with no extra code from you.

Reading items

rust
let marks = vec![72, 85, 64];
let second = marks[1];                 // 85; panics if the index is too big
match marks.get(7) {
    Some(m) => println!("{m}"),
    None => println!("no such student"),  // printed
}
println!("{:?} {:?}", marks.first(), marks.last()); // Some(72) Some(64)
Use [i] when the index is surely valid; use get(i) when it might not be.

Looping

rust
let mut prices = vec![100, 250, 75];

for p in &prices {           // read: p is &i32
    print!("{p} ");
}
println!();

for p in &mut prices {       // change: p is &mut i32
    *p += *p * 18 / 100;     // add 18% GST
}
println!("{:?}", prices);     // [118, 295, 88]

for p in prices {            // consume: prices is moved and gone afterwards
    let _ = p;
}
for x in &v reads, for x in &mut v changes, for x in v takes ownership of the items.

The borrow rule you will hit

output
let mut v = vec![1, 2, 3];
let first = &v[0];
v.push(4);              // error[E0502]: cannot borrow `v` as mutable
println!("{first}");
push might move the buffer, leaving first dangling. Copy the value out (let first = v[0];) or finish using it before the push.

Useful methods

MethodWhat it does
push(x) / pop()Add to the end / remove from the end (pop returns an Option)
insert(i, x) / remove(i)Add or remove at a position (shifts the rest; slower for big Vecs)
len() / is_empty()Number of items / whether there are none
contains(&x)Whether a value is in the Vec
sort() / sort_by_key(f)Sort in place
dedup()Remove consecutive duplicates (sort first to remove all)
retain(f)Keep only items where f returns true
extend(other)Append all items of another collection
rust
let mut ids = vec![5, 3, 5, 1, 3];
ids.sort();          // [1, 3, 3, 5, 5]
ids.dedup();         // [1, 3, 5]
ids.retain(|&x| x != 3);
println!("{:?}", ids);   // [1, 5]
retain takes a closure, a small inline function (module 8).

Common mistakes

  • Indexing with an i32: v[i] needs a usize. Declare loop counters as usize or convert.
  • Calling dedup() without sorting first, and expecting all duplicates gone.
  • Holding a reference into the Vec while pushing (E0502).
  • Looping with for x in v and then trying to use v again. Use &v unless you mean to consume it.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Vec<T>: growable lists · 1/6

Vec<T>

Vec is Rust's growable list. All items have the same type, and they live on the heap.

Prefer a video by a teacher? Find free videos on “rust vec vector tutorial push get iterate” on YouTube ↗

In real life: A daily attendance list

A school attendance app stores the roll numbers of students present today in a Vec<u32>, because the number changes every day. The teacher adds late-comers with push, removes a wrong entry with retain, sorts the list for the register, and checks whether a student was present with contains.

rust
fn main() {
    let mut present: Vec<u32> = vec![12, 3, 27, 8];
    present.push(15);                 // late-comer
    present.retain(|&r| r != 27);     // marked by mistake
    present.sort();
    println!("{:?}", present);         // [3, 8, 12, 15]
    println!("Roll 8 present: {}", present.contains(&8));
    println!("Total: {}", present.len());
}
contains takes a reference to the value it looks for.

Practice (0/3 done)

Task 1 · Question

What does this print? let mut v = vec![4, 1, 4, 2, 1]; v.sort(); v.dedup(); println!("{:?}", v);

Task 2 · Question

Which line reads index 10 of a 3-item Vec without panicking?

Task 3 · Practice

Write a program that keeps a Vec<String> of grocery items. Add five items, remove one by name with retain, sort them, print them numbered (1. atta, 2. dal...) using enumerate, and print whether "sugar" is in the list.

Quick quiz

Question 1

1.What does v.pop() return?

Question 2

2.Which loop lets you change items in place?

Question 3

3.Why can a reference into a Vec become invalid after push?

Question 4

4.What type must an index be?

Question 5

5.What does vec![0; 3] create?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What does v.pop() return?

Answer: An Option: Some(last item) or None if empty

pop returns Option<T> because the Vec may be empty.

Which loop lets you change items in place?

Answer: for x in &mut v

&mut v gives mutable references to each item.

Why can a reference into a Vec become invalid after push?

Answer: push may reallocate and move all items

When capacity runs out, the items move to a new buffer.

What type must an index be?

Answer: usize

Indexes are usize.

What does vec![0; 3] create?

Answer: [0, 0, 0]

vec![value; count] repeats the value.

What does len() return for a String?Related

Answer: Number of bytes

len() counts bytes of UTF-8 data.

From Slices and strings

Why does Rust forbid a &mut while & references exist?Related

Answer: So readers never see the value change under them (no data races)

Exclusive access for writers prevents data races and similar bugs.

From References and borrowing

Which is a valid array type for five f64 values?Related

Answer: [f64; 5]

Array types are written [type; length].

From Compound types: tuples and arrays

What is the best fix for "returns a reference to data owned by the current function"?Related

Answer: Return an owned value

Move ownership out instead of borrowing a local.

From Interview questions: ownership, borrowing and lifetimes

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 1 more topic in “Error handling and collections” before its exam: HashMap and HashSet.
  2. Module 6 exam: Error handling and collections · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Modules, crates, traits and generics. 50 topics left in the course before the final exam.

← Previous: Custom error types