Start learning free

LESSON 100 OF 414 · ARRAYS I

Accessing Vec Elements in Rust: Indexing and get()

Lesson Read the full explanation

We can access the data inside a Vec using indices and the bracket notation ([]), just like we do for static arrays.

Vectors also use zero-based indexing, so the first element in a vector has an index of 0.

let array = vec![50, 60, 70];

println!("{}", array[0]); // Output: 50

let data = array[1];
println!("{}", data); // Output: 60

Assignment
Follow the Coding Tutorial and let's play with some arrays.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 3
    Ctrl + Enter to check

    RUST · ARRAYS I

    Accessing Elements in Rust, explained

    Reading an element

    A Vec gives you its elements by position, using square brackets after its name, exactly as an array does. Positions start at zero: the first element is at index 0, the second at 1, and a vector with n elements has its last element at index n - 1.

    let array = vec![50, 60, 70];
    
    println!("{}", array[0]); // 50
    
    let data = array[1];
    println!("{}", data); // 60
    

    The expression array[1] has the value of the element, so it can be printed, stored in a variable, added to another value or passed to a function. The index itself must be a usize. A literal such as 1 is inferred as one, while an i32 variable must be converted with as usize before it can index.

    Indexing and ownership

    Indexing with [] reads the element in place. For simple types like integers and for string slices (&str), the value is copied, and you get your own copy. Those types are cheap to copy, and Rust does it for you. For a vector of String, though, let s = names[0]; won't compile, because moving a String out of a vector would leave a hole. Borrow it with &names[0] or clone it with names[0].clone().

    The lesson's exercise

    The starting code has two vectors:

    let fruits = vec!["mango", "kiwi", "grapefruit"];
    let ages = vec![14, 32, 50, 21];
    

    You print three things, each with a println! call. Its first argument is a format string, where each {} is replaced by the next argument.

    1. The second fruit. Zero-based indexing puts it at index 1: println!("{}", fruits[1]); prints kiwi. Index 2 would be the third fruit.
    2. The sum of the first three ages. Index 0, 1 and 2 hold 14, 32 and 50. The expression is evaluated before printing, so the call receives the finished sum, 96.
    3. The last age minus the first. With four ages, the last is at index 3, and 21 - 14 is 7.
    let fruits = vec!["mango", "kiwi", "grapefruit"];
    let ages = vec![14, 32, 50, 21];
    
    println!("{}", fruits[1]);
    println!("{}", ages[0] + ages[1] + ages[2]);
    println!("{}", ages[3] - ages[0]);
    

    The output is kiwi, 96 and 7, one per line.

    The last element and safe access

    Because a vector can change size, the last index isn't a fixed number in general. Compute it from the length: ages[ages.len() - 1] is the last age, 21. The length is a usize, which can't go below zero. For an empty vector, len() - 1 underflows. In the optimized build the lessons use it wraps to a huge number, and in a debug build it panics. Either way the program fails.

    Two methods avoid that and avoid panics, because they return an Option:

    • get(i) gives Some(&element) when the index exists and None otherwise. For vec![1, 2, 3], get(1) is Some(2) and get(10) is None.
    • last() gives the final element, or None for an empty vector.

    Plain indexing is right when you know the index is valid, as it is in this exercise. Prefer get when the index comes from data you don't control.

    Out-of-range indexes

    Rust checks every index when the program runs. If the index is past the end, the program panics with a message such as index out of bounds: the len is 3 but the index is 5. It never reads memory outside the vector. Negative indexes don't exist: ages[-1] is a compile error, since the index must be unsigned.

    Common mistakes

    • Off-by-one. The second item is at index 1, and the item at len() doesn't exist.
    • Indexing with an i32. The compiler reports that the vector can't be indexed by i32. Use a usize, or convert deliberately with as usize.
    • Forgetting the format string. println!(fruits[1]) is an error. The first argument must be a literal such as "{}".
    • Printing a whole vector with {}. Use {:?} for the full vector, which prints [14, 32, 50, 21].

    Key takeaways

    • v[i] reads the element at position i; the first position is 0 and the last is len() - 1.
    • Indexes have type usize, and an out-of-range index panics.
    • Use get(i) or last() when the element might not exist.
    • An indexed element is an ordinary value you can add, compare or print.
    Keep going with RustAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free