Taking part of a Vec
Sometimes you need only part of a Vec, such as the first few items. A range of indexes picks that part. The range 1..4 runs from 1 up to, but not including, 4, so letters[1..4] covers the items at indexes 1, 2 and 3.
Leave out the start to begin at index 0, or the end to go to the very end:
let letters = vec!["a", "b", "c", "d", "e"];
let middle = letters[1..4].to_vec(); // ["b", "c", "d"]
let head = letters[..2].to_vec(); // ["a", "b"]
let tail = letters[3..].to_vec(); // ["d", "e"]
Printed with {:?}, those three are ["b", "c", "d"], ["a", "b"] and ["d", "e"]. A range such as 2..2 is empty and gives []. Writing 1..=3 includes the end, so it gives the same items as 1..4.
Why to_vec
On its own, letters[1..4] is a slice: it only borrows those items from letters, and it can't be stored in a variable of type Vec. Assigning it to one is a compile error ("expected Vec<&str>, found [&str]"). Adding .to_vec() copies the items into a new Vec of its own. The original vector stays as it was.
Ranges that go too far
A range past the length makes the program panic. With five letters, letters[3..9] stops with "range end index 9 out of range for slice of length 5". A range whose start is larger than its end panics too.
The copy is independent
Because to_vec() copies the items, changing one vector later doesn't touch the other. With a = vec![1, 2, 3, 4, 5], take b = a[1..3].to_vec(), which is [2, 3]. After a[1] = 99;, a is [1, 99, 3, 4, 5] and b is still [2, 3].
The bounds can be variables too. If n is 2, then a[..n] is the first two items and a[n..] is everything from index 2 on. The two pieces always add up to the whole vector, which makes this a handy way to split a list in two.
The task, step by step
The five runners are ["Ana", "Ben", "Cleo", "Dan", "Eve"]. The podium is the first three, so the range is 0..3, which covers indexes 0, 1 and 2. Everyone else runs from index 3 to the end, so the range is 3...
let runners = vec!["Ana", "Ben", "Cleo", "Dan", "Eve"];
let podium = runners[0..3].to_vec();
let rest = runners[3..].to_vec();
println!("{} {} {}", podium[0], podium[1], podium[2]);
println!("{} {}", rest[0], rest[1]);
println!("{}", runners.len());
It prints:
Ana Ben Cleo
Dan Eve
5
The last line shows that runners still has all five items.
Counting the items
The number of items in i..j is j - i, so 0..3 has three items and 3.. on a vector of five has two. This is why the lesson prints Dan Eve as the second line: indexes 3 and 4 are what is left after the podium. The two ranges 0..3 and 3.. meet at 3 without overlapping or skipping an index, because the end of one range is not included and the start of the other is. Splitting at a single number like this is the safest way to cut a vector into two parts.
Common mistakes
- Forgetting that the end of the range is not included:
0..3gives three items, not four. - Leaving out
.to_vec()and trying to store the slice as aVec. - Using an end past the length of the vector.
Key takeaways
v[i..j]covers indexesiup to, not including,j..to_vec()makes a separate copy, so the original is unchanged.- A range outside the vector panics.
