RustArena

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

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