Start learning free

LESSON 118 OF 679 · ARRAYS I

Slicing a Vec in Rust

Lesson Read the full explanation

TL ; DR:

v[i..j].to_vec() is a new Vec with the items from index i up to, not including, j. The original doesn't change.


let letters = vec!["a", "b", "c", "d", "e"];

let middle = letters[1..4].to_vec();
// middle is ["b", "c", "d"]

// letters is still ["a", "b", "c", "d", "e"]


Full lesson:

Sometimes you need only part of a Vec, like the first few items. A range of indexes picks that part.

1..4 is the range from 1 up to, not including, 4. So letters[1..4] has the items at 1, 2 and 3.

Leave out the start to begin at index 0. Leave out the end to go to the very end:

let tail = letters[3..].to_vec();
// tail is ["d", "e"]

On its own, letters[1..4] only borrows those items from letters. Then .to_vec() copies them into a new Vec of its own.

The original Vec stays as it was.

A range past the length makes the program panic. So letters[3..9] stops the program with an error.


Your task

runners holds a race's runners, in the order they finished.

Put the first three in a new Vec named podium. Put everyone else, from index 3 to the end, in one named rest.

The code below prints both, then the length of runners.

Expected output:

Ana Ben Cleo
Dan Eve
5
STEP 1 OF 2
    Ctrl + Enter to check

    RUST · ARRAYS I

    Array Slicing in Rust, explained

    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..3 gives three items, not four.
    • Leaving out .to_vec() and trying to store the slice as a Vec.
    • Using an end past the length of the vector.

    Key takeaways

    • v[i..j] covers indexes i up to, not including, j.
    • .to_vec() makes a separate copy, so the original is unchanged.
    • A range outside the vector panics.
    Keep going with Rust500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free