What len() does
The len() method of a Vec returns how many elements it holds. The count is stored with the vector, so asking for it is instant, however long the vector is. The result changes whenever the vector grows or shrinks:
let mut our_array = vec![50, 40, 30];
println!("{}", our_array.len());
our_array.pop();
println!("{}", our_array.len());
3
2
The same method works on fixed-size arrays and on slices, so the habit carries over. An empty vector has length 0, and is_empty() is the idiomatic way to test for it.
The type of the length
len() returns a usize, an unsigned integer whose size matches the machine's pointer width. It is the type Rust requires for indexing, which is why you can use the length directly in an index expression without any conversion.
Because usize is unsigned, it can never be negative. That matters for arithmetic on lengths, covered below.
Using the length in a loop
The range 0..ages.len() excludes its upper bound, so it produces exactly the valid indexes. That makes it the standard way to walk over a vector by position:
let ages = vec![14, 32, 50, 21];
let mut total = 0;
for i in 0..ages.len() {
total += ages[i];
}
println!("{}", total);
117
Note that len() on the vector counts elements, not characters. For a vector of strings, fruits.len() is the number of strings, while fruits[0].len() is the byte length of the first string: 5 for "mango".
Reaching items from the end
Rust has no negative indexes, so there is no shortcut like "index -1 means last". Instead, compute the position from the length. A vector with len() elements has valid indexes 0 to len() - 1, so the last element is at len() - 1, the second to last at len() - 2, and so on:
let our_array = vec![50, 40, 30];
let size = our_array.len();
println!("{}", our_array[size - 1]);
println!("{}", our_array[size - 2]);
30
40
For the last element specifically, last() is often neater. It returns an Option that is None for an empty vector, so it can't panic.
Gotchas in Rust
Subtracting from zero
If the vector is empty, len() - 1 is 0usize - 1. An unsigned number can't go below zero, so the lesson's optimized builds wrap around to a huge number, and a debug build panics with an overflow error instead. Either way, the following index is out of bounds and the program panics. Check is_empty() or use last() when the vector might have no elements.
With an empty vector the optimized build reports index out of bounds: the len is 0 but the index is 18446744073709551615. A safe version tests first:
fn show(v: &Vec<i32>) {
if v.is_empty() {
println!("empty");
} else {
println!("last = {}", v[v.len() - 1]);
}
println!("{:?}", v.last());
}
Called with vec![5, 6] it prints last = 6 and then Some(6). Called with an empty vector it prints empty and then None. The second line shows the type last() returns: an Option, which holds a value or nothing.
Using the length itself as an index
The length is one more than the last valid index. Writing v[v.len()] always panics, with a message such as index out of bounds: the len is 4 but the index is 4.
Counting from 1 versus 0
The length counts elements starting from 1, while indexes start from 0. That one-off difference is the source of most off-by-one mistakes with vectors.
The lesson's exercise
The starter code defines two immutable vectors: fruits with three strings and ages with four numbers. The exercise asks for three prints.
- Print the number of fruits. Call
fruits.len()insideprintln!with the{}placeholder. It prints 3. - Print the last age. With four elements the last valid index is 3, which is
ages.len() - 1. It prints 21. - Print the second to last age. Step back one more position with
ages.len() - 2. It prints 50.
The complete code:
let fruits = vec!["mango", "kiwi", "grapefruit"];
let ages = vec![14, 32, 50, 21];
println!("{}", fruits.len());
println!("{}", ages[ages.len() - 1]);
println!("{}", ages[ages.len() - 2]);
The output is:
3
21
50
Neither vector is declared mut, because reading the length and reading elements doesn't change anything.
Key takeaways
v.len()returns the number of elements as ausize.- The last valid index is
v.len() - 1;v[v.len()]always panics. - Rust has no negative indexes, so count back from the length instead.
- On an empty vector,
len() - 1underflows; guard withis_empty()or uselast().
