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.
- Print the second fruit. The second item is at index
1, so the call isprintln!("{}", fruits[1]);. It printskiwi. Index2would give the third item,grapefruit. - Print the sum of the first three ages. Those are at indexes
0,1and2. Add them inside the call: 14 + 32 + 50 =96. - 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
i32variable can't be used as an index. The compiler says slices are indexed byusize. Use ausize, or convert withas 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, useages[ages.len() - 1], orages.last(), which returns anOption. - 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 typeusize.- 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
getgives a safeOption.
