Step 2 of 7
Reading elements with [] and get
There are two ways to read an element. Indexing, v[i], gives you the element directly and panics if i is past the end. v.get(i) returns an Option: Some(&element) or None.
fn main() {
let podium = vec!["Ferris", "Corro", "Bunny"];
println!("winner: {}", podium[0]);
println!("third: {}", podium[2]);
match podium.get(5) {
Some(name) => println!("sixth: {name}"),
None => println!("no sixth place"),
}
println!("{:?} {:?}", podium.first(), podium.last());
}
winner: Ferris
third: Bunny
no sixth place
Some("Ferris") Some("Bunny")
Indexes start at 0, so the last valid index is len() - 1. first() and last() are get(0) and get(len - 1) with names, and return None on an empty vector.
Here's what happens when indexing goes past the end:
fn main() {
let podium = vec!["Ferris", "Corro", "Bunny"];
println!("checking place 4");
println!("{}", podium[3]);
}
checking place 4
The program stops with this message, plus the file and line of the bad index:
index out of bounds: the len is 3 but the index is 3
A panic stops the program with a message. Unlike C or C++, Rust never reads whatever memory happens to be past the end: it always checks.
Which one to use
- Use
v[i]when an index past the end would be a bug in your own code (a loop bound you control). The panic points straight at the bug. - Use
v.get(i)when the index comes from outside: user input, a file, a request. A missing element is then a normal situation you handle withmatch,if letorlet ... else.
Indexes are usize
Indexes and lengths have the type usize. An i32 index doesn't compile:
fn main() {
let v = vec![10, 20, 30];
let i: i32 = 1;
println!("{}", v[i]);
}
error[E0277]: the type `[{integer}]` cannot be indexed by `i32`
Make the variable a usize, or convert with i as usize when you know it isn't negative.
Common mistake: moving out by index
v[0] on a Vec<i32> copies the number. On a Vec<String> it would have to move the String out and leave a hole, which Rust doesn't allow:
fn main() {
let names = vec![String::from("Ana"), String::from("Bo")];
let first = names[0];
println!("{first}");
}
error[E0507]: cannot move out of index of `Vec<String>`
Borrow it (let first = &names[0];) or copy it explicitly (names[0].clone()). In the same way, get gives you a reference (Option<&String>), never the value itself.
Your task
A game inventory has numbered slots. Write fn inventory_line(items: &[&str], slot: usize) -> String that returns "slot 2: shield" for an existing slot and "slot 9: empty" for a slot past the end. Use get, so a big slot number can't crash the game.
Challenge 2
The first input line lists player names separated by spaces. Every line after that holds an index. For each index print the player's name, or no player at index N if there's no such player. The reading code is done; write the lookup with get.
Challenge 3
Write fn median(sorted: &[f64]) -> Option<f64> for a slice that is already sorted. Return None for an empty slice. With an odd number of values the median is the middle one; with an even number it's the average of the two middle values ([1.0, 2.0, 3.0, 10.0] gives 2.5).
Previous: Creating and growing a Vec Next: Looping: &v, &mut v and v