Rust Vectors
A Vec is a growable list of values of one type. No fixed count is set in advance.
Start a Vec, then push
vec! starts the list with items. push adds one more at the end:
let mut v = vec![10, 20, 30];
v.push(40);Read by position, or safely with get
v[0] reads the first item and len() counts them. get answers None instead of stopping the program when the position is past the end:
let v = vec![10, 20, 30];
println!("first = {} of {}", v[0], v.len());
println!("safe = {:?}", v.get(9));Visit and change each item
for over &mut v hands you each item as a reference. The star writes through it to the real item:
let mut v = vec![1, 2, 3];
for x in &mut v {
*x += 10;
}
println!("{:?}", v);Ask whether an item is there
let v = vec![10, 20, 30];
println!("has 20 = {}", v.contains(&20));
println!("has 99 = {}", v.contains(&99));Insert and remove in the middle
push and pop work at the end. insert and remove work anywhere. The items after the spot shift over to make room. Or they shift back to close the gap:
let mut v = vec![10, 30, 40];
v.insert(1, 20);
println!("after insert = {:?}", v);
let taken = v.remove(2);
println!("took {}, left = {:?}", taken, v);A Vec works as a stack
Add and remove at the same end and the Vec becomes a stack. The last one on is the first one off:
plates.push("bottom");
plates.push("middle");
plates.push("top");
println!("first off = {:?}", plates.pop());Example
fn main() {
let mut scores = vec![10, 20, 30];
scores.push(40);
let total: i32 = scores.iter().sum();
println!("{:?} total={} avg={}", scores, total, total / scores.len() as i32);
println!("get(10) = {:?}", scores.get(10));
}Key points
- v[i] reads an item, but stops the program if i is out of range
- With no items, Rust has nothing to guess the type from.
- So an empty Vec::new() needs a type note, like let v: Vec<i32> = Vec::new();
- When a Vec goes out of scope, the Vec and every item inside it are dropped together
- A Vec is three parts together.
- One part is a pointer to its heap storage.
- One part is a length: how many items it holds now.
- One part is a capacity: how many items fit in the reserved storage.
- Use v.swap_remove(i) when the order does not matter.
- It is faster.
- The last item jumps straight into the gap instead of everything shifting.
- Items can keep arriving one by one: the Vec grows to hold each new item.
In this example, scores starts as a Vec with 10, 20, 30. push adds 40 at the end. Then .iter().sum() borrows each score and adds them: 100. scores.len() is 4, so the average is 25. The last line uses get(10): there is no item at position 10, so it calmly gives None. Compare that with scores[10], which would stop the program with an error.
Note
A Vec keeps a little spare room so push stays fast.
Vec::with_capacity(n) reserves that room in advance when you know roughly how many items are coming.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
What is the safe way to read a Vec item that might not exist?