Slices

Let's go back to the memory layout of a Vec:

#![allow(unused)]
fn main() {
let mut numbers = Vec::with_capacity(3);
numbers.push(1);
numbers.push(2);
}
      +---------+--------+----------+
Stack | pointer | length | capacity | 
      |  |      |   2    |    3     |
      +--|------+--------+----------+
         |
         |
         v
       +---+---+---+
Heap:  | 1 | 2 | ? |
       +---+---+---+

We already remarked how String is just a Vec<u8> in disguise.
The similarity should prompt you to ask: "What's the equivalent of &str for Vec?"

&[T]

[T] is a slice of a contiguous sequence of elements of type T.
It's most commonly used in its borrowed form, &[T].

There are various ways to create a slice reference from a Vec:

#![allow(unused)]
fn main() {
let numbers = vec![1, 2, 3];
// Via index syntax
let slice: &[i32] = &numbers[..];
// Via a method
let slice: &[i32] = numbers.as_slice();
// Or for a subset of the elements
let slice: &[i32] = &numbers[1..];
}

Vec implements the Deref trait using [T] as the target type, so you can use slice methods on a Vec directly thanks to deref coercion:

#![allow(unused)]
fn main() {
let numbers = vec![1, 2, 3];
// Surprise, surprise: `iter` is not a method on `Vec`!
// It's a method on `&[T]`, but you can call it on a `Vec` 
// thanks to deref coercion.
let sum: i32 = numbers.iter().sum();
}

Memory layout

A &[T] is a fat pointer, just like &str.
It consists of a pointer to the first element of the slice and the length of the slice.

If you have a Vec with three elements:

#![allow(unused)]
fn main() {
let numbers = vec![1, 2, 3];
}

and then create a slice reference:

#![allow(unused)]
fn main() {
let slice: &[i32] = &numbers[1..];
}

you'll get this memory layout:

                  numbers                          slice
      +---------+--------+----------+      +---------+--------+
Stack | pointer | length | capacity |      | pointer | length |
      |    |    |   3    |    4     |      |    |    |   2    |
      +----|----+--------+----------+      +----|----+--------+
           |                                    |  
           |                                    |
           v                                    | 
         +---+---+---+---+                      |
Heap:    | 1 | 2 | 3 | ? |                      |
         +---+---+---+---+                      |
               ^                                |
               |                                |
               +--------------------------------+

&Vec<T> vs &[T]

When you need to pass an immutable reference to a Vec to a function, prefer &[T] over &Vec<T>.
This allows the function to accept any kind of slice, not necessarily one backed by a Vec.

For example, you can then pass a subset of the elements in a Vec. But it goes further than that—you could also pass a slice of an array:

#![allow(unused)]
fn main() {
let array = [1, 2, 3];
let slice: &[i32] = &array;
}

Array slices and Vec slices are the same type: they're fat pointers to a contiguous sequence of elements. In the case of arrays, the pointer points to the stack rather than the heap, but that doesn't matter when it comes to using the slice.

Exercise

The exercise for this section is located in 06_ticket_management/10_slices