Start learning free

LESSON 99 OF 414 · ARRAYS I

Accessing Static Array Elements in Rust: Zero-Based Indexing

Lesson Read the full explanation

Arrays are ordered, meaning each element has a numbered position known as its index. We access an array element by referring to its index number.

Arrays use zero-based indexing, so the first element in an array has an index of 0, the second element has an index of 1, etc.

We're using bracket notation ([]) with the index after the name of the array to access the element:

let animals = ["cat", "dog", "parrot"];

println!("{}", animals[0]); // Output: cat
println!("{}", animals[1]); // Output: dog
println!("{}", animals[2]); // Output: parrot

Assignment
Follow the Coding Tutorial and let's practice with accessing elements!


Hint
Look at the examples above if you get stuck.


STEP 1 OF 3
    Ctrl + Enter to check

    RUST · ARRAYS I

    Accessing Static Array Elements in Rust, explained

    Indexes and positions

    Every element of an array sits at a numbered position called its index. Rust counts from zero, so the first element has index 0, the second has index 1 and so on. An array of n elements has valid indexes 0 through n - 1. The last element is always at index n - 1, never at n.

    You read an element with square brackets after the name: name[index]. The index must be a usize, Rust's unsigned integer type for sizes and positions. A plain number written in the brackets is inferred to be one.

    let animals = ["cat", "dog", "parrot"];
    
    println!("{}", animals[0]); // cat
    println!("{}", animals[1]); // dog
    println!("{}", animals[2]); // parrot
    

    These work the same way for a fixed array and for a Vec, because both support the same bracket notation. The lesson's data is a Vec built with vec!, and the indexing is identical.

    Using the value you read

    An indexed element is an ordinary value of the element type, so you can use it wherever such a value is allowed. For a vector of integers, ages[0] + ages[1] is a normal addition. You can also store an element in a variable: let first = ages[0];. For types that are cheap to copy, such as integers, this copies the value out of the array. For types that own heap data, such as String, indexing can't move the value out: let s = names[0]; is a compile error, and you borrow it with &names[0] or copy it with names[0].clone().

    Printing with println!

    println! takes a format string first. Each {} in it is replaced by the next argument, so println!("{}", fruits[1]) prints the item at index 1. An expression is evaluated before it is printed, so println!("{}", ages[0] + ages[1]) prints the sum, not the two numbers.

    The lesson's exercise

    The starting code defines two vectors:

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

    Three tasks follow.

    1. Print the second fruit. The second item is at index 1, so the call is println!("{}", fruits[1]);. It prints kiwi. Index 2 would give the third item, grapefruit.
    2. Print the sum of the first three ages. Those are at indexes 0, 1 and 2. Add them inside the call: 14 + 32 + 50 = 96.
    3. Print the last age minus the first. There are four ages, so the last is at index 3. The difference is 21 - 14 = 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 program prints three lines: kiwi, 96 and 7.

    What happens with a bad index

    Rust checks every index. If the index is past the end, the program doesn't read some other memory: it stops.

    • At run time: with a vector of 3 items and an index computed while the program runs, v[5] ends the program with a panic, index out of bounds: the len is 3 but the index is 5.
    • At compile time: when the compiler can see that the index is out of range, for example a[5] on an array literal of 3 items, it refuses to build the program and reports that the operation will panic at run time.
    • Wrong index type: an i32 variable can't be used as an index. The compiler says slices are indexed by usize. Use a usize, or convert with as usize.

    When you aren't sure an index is valid, get returns an Option instead of panicking: v.get(1) is Some(&value) for a valid index and v.get(10) is None.

    Common mistakes

    • Counting from one. The second item is index 1. The most common error is writing index 2 for it and getting the third.
    • Using the length as an index. For four ages, index 4 doesn't exist. The last valid index is 3, which is len() - 1.
    • Negative indexes. There is no ages[-1] as in some other languages. A negative literal isn't a valid index. To reach the last element, use ages[ages.len() - 1], or ages.last(), which returns an Option.
    • Forgetting the format string. println!(fruits[1]) doesn't compile. The first argument must be a string literal such as "{}".

    Key takeaways

    • Indexes start at 0, and the last index is the length minus one.
    • name[index] reads an element, and the index has type usize.
    • Elements can be used in expressions directly, so sums and differences go inside println!.
    • Out-of-range indexes panic instead of reading bad memory, and get gives a safe Option.
    Keep going with RustAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free