Rust Vectors
A vector, written Vec, is a list that can grow and shrink while the program runs. If an array is a box with a fixed number of slots, a vector is a backpack you can keep putting things into. Vectors are probably the collection you will use most in Rust.
Creating a vector and adding items
The vec! macro makes a vector with some starting items. Vec::new() makes an empty one. push adds an item to the end:
fn main() {
let mut shopping = vec!["milk", "bread"];
shopping.push("eggs");
shopping.push("rice");
println!("{:?}", shopping);
println!("{} items, first is {}", shopping.len(), shopping[0]);
}["milk", "bread", "eggs", "rice"] 4 items, first is milk
All items in a vector must have the same type. Rust works the type out from the first items: here it is Vec<&str>, a vector of text slices. The part in angle brackets says what kind of item the vector holds.
Removing items
pop takes the last item off. Because the vector might be empty, it gives back an Option: Some(item) or None. remove takes out the item at a position and shifts the rest along:
fn main() {
let mut stack = vec![1, 2, 3, 4];
let top = stack.pop();
println!("Popped {:?}, left {:?}", top, stack);
let second = stack.remove(1);
println!("Removed {}, left {:?}", second, stack);
}Popped Some(4), left [1, 2, 3] Removed 2, left [1, 3]
Reading safely with get
v[10] on a short vector stops the program. When an index might be out of range, get is the polite way to ask. It gives Some(&item) if the item exists and None if not, and you decide what to do:
fn main() {
let colours = vec!["red", "green", "blue"];
for i in [1, 5] {
match colours.get(i) {
Some(c) => println!("Position {} is {}", i, c),
None => println!("There is nothing at position {}", i),
}
}
}Position 1 is green There is nothing at position 5
Looping, changing and sorting
Loop with for item in &v to read, and for item in &mut v to change each item in place. The * in *n means "the value this reference points at". Vectors also know how to sort themselves:
fn main() {
let mut prices = vec![40, 15, 99, 23];
for p in &mut prices {
*p += 5;
}
println!("With delivery: {:?}", prices);
prices.sort();
println!("Sorted: {:?}", prices);
let total: i32 = prices.iter().sum();
println!("Total: {}", total);
}With delivery: [45, 20, 104, 28] Sorted: [20, 28, 45, 104] Total: 197
Building a vector from input
A very common pattern is to start with Vec::new() and push items as they arrive, for example numbers typed by the user:
use std::io;
fn main() {
let mut numbers: Vec<i32> = Vec::new();
println!("Type 3 numbers:");
for _ in 0..3 {
let mut line = String::new();
io::stdin().read_line(&mut line).expect("could not read");
numbers.push(line.trim().parse().expect("a whole number"));
}
println!("You typed {:?}, the biggest is {}", numbers, numbers.iter().max().unwrap());
}8 42 17
Type 3 numbers: You typed [8, 42, 17], the biggest is 42
Practice exercises
- Make an empty vector of names, push four names, and print them sorted.
- Ask for 5 marks, store them in a vector, and print the average.
- Use
getto safely print the 10th item of a short vector, with a friendly message when it is missing.