Intermediate · Error handling and collections · topic 25 of 50 · 25 min
Vec<T>: growable lists
Explanation
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.
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());How a Vec looks in memory
orders (stack) heap buffer (capacity 4)
ptr -------------> [101][102][ free ][ free ]
len = 2
capacity = 4If you know roughly how many items you will add, Vec::with_capacity(n) reserves space once and avoids repeated reallocations.
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
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)Looping
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;
}The borrow rule you will hit
let mut v = vec![1, 2, 3];
let first = &v[0];
v.push(4); // error[E0502]: cannot borrow `v` as mutable
println!("{first}");Useful methods
| Method | What 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 |
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]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 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.
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());
}Practice (0/3 done)
What does this print? let mut v = vec![4, 1, 4, 2, 1]; v.sort(); v.dedup(); println!("{:?}", v);
Which line reads index 10 of a 3-item Vec without panicking?
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
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- HashMap and HashSetError handling and collections · same module
- Result and the ? operatorError handling and collections · same module
- Compound types: tuples and arraysTypes, control flow and functions
- Interview questions: ownership, borrowing and lifetimesRust careers and interviews
- Copy and CloneOwnership: Rust's big idea
- IteratorsClosures, iterators and smart pointers
Questions people ask about this
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
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.
Which is a valid array type for five f64 values?Related
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 more topic in “Error handling and collections” before its exam: HashMap and HashSet.
- Module 6 exam: Error handling and collections · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Modules, crates, traits and generics. 50 topics left in the course before the final exam.