Step 3 of 6
Arrays: a fixed row of values
A tuple groups a few values of different types. An array holds a fixed number of values of the same type, in a row: seven daily temperatures, twelve monthly totals, the 64 squares of a chessboard.
fn main() {
let temps = [18, 21, 19, 25, 23];
println!("first: {}", temps[0]);
println!("third: {}", temps[2]);
println!("count: {}", temps.len());
println!("all: {:?}", temps);
}
first: 18
third: 19
count: 5
all: [18, 21, 19, 25, 23]
- Square brackets make an array. Its type is written
[i32; 5]: the element type, a semicolon, and the length. The length is part of the type, so[i32; 5]and[i32; 6]are different types. temps[0]is indexing: the element at position 0. The position is called the index. Indexes start at 0, so the five elements are at indexes 0 to 4, and the last one is attemps.len() - 1..len()gives the number of elements, as ausize(the unsigned integer type Rust uses for sizes and positions).{:?}prints the whole array.
The same value many times
[0; 10] is an array of ten zeros: [value; count]. It's handy for counters:
fn main() {
let mut votes = [0; 3];
votes[1] += 1;
votes[1] += 1;
votes[2] += 1;
println!("{:?}", votes);
}
[0, 2, 1]
Changing an element changes the array, so it needs let mut. Even then the length can't change: an array can't grow or shrink. (That's what Vec is for, at the end of this module.)
Out of bounds
What if you ask for an element that isn't there? Rust always checks. If the compiler can see the mistake, it refuses to compile (error: this operation will panic at runtime). If the index is only known when the program runs, the program panics: it stops at once with a message, instead of carrying on with garbage.
fn main() {
let scores = [10, 20, 30];
let last = scores.len(); // a classic slip: the last index is len() - 1
println!("checking...");
println!("{}", scores[last]);
}
checking...
The panic message reads index out of bounds: the len is 3 but the index is 3, with the line number. In C, the same mistake silently reads whatever memory comes next, which is a classic source of security holes. In Rust it's a clear crash at the exact spot.
Common mistakes
- Using
len()as the last index. The last element is atlen() - 1. - Forgetting
mut:temps[0] = 5;on a non-mutarray gives error E0594,cannot assign to `temps[_]`, as `temps` is not declared as mutable. - The wrong length in a type:
let temps: [i32; 3] = [18, 21];givesexpected an array with a size of 3, found one with a size of 2. - Indexing with an
i32. Indexes must beusize:
fn main() {
let temps = [18, 21, 19];
let i: i32 = 2;
println!("{}", temps[i]);
}
error[E0277]: the type `[{integer}]` cannot be indexed by `i32`
Declare the index as usize, or convert it with temps[i as usize] (only when you know it isn't negative).
Your task
The array holds a week of daily sales. Print the first day's sales, the last day's sales, and the number of days. Find the last index with .len() so the code would still work if the array had a different length:
first day: 120
last day: 66
days: 7
Challenge 2
Four checkout lanes count waiting customers. Fill the blanks so the array can be changed and the last index is computed from the length. The program should print [3, 0, 5, 1].
Challenge 3
Write first_and_last(values), which returns the first and the last element of a five-element array as a tuple. For example first_and_last([4, 8, 15, 16, 23]) returns (4, 23).
Passing an array of numbers to a function copies the whole array, so the function can read it freely. (Module 11 shows slices, which let one function accept arrays of any length.)
Previous: Destructuring, and returning several values Next: Looping over an array