Arrays and Slices

From Rust Community Wiki

An array is a fixed-size sequence of values of the same type. They are written with [T; N], where T is the type the array contains and N is the number of elements in the array. A slice is similar, but its size is only known at runtime, so they are written as just [T]. Arrays and slices cannot grow or shrink; their size is fixed from creation.

Example

// the length of arrays is known at compile time
let array: [i32; 4] = [1, 2, 4, 8];
// so we can fully destructure it:
let [a, b, c, d] = array;

// arrays can be coerced into slices:
let slice: &[i32] = &array;
// by indexing an array with a range, you can get a part of it as a range:
let slice: &[i32] = &array[2..8];
The variable array has the type [i32; 4]. Because its length is part of its type, the compiler ensures that it can't be assigned an array with the wrong length.

Slices are dynamically sized. This means that they can only exist behind a reference or in pointer type such as BoxThis links to official Rust documentation. There are two safe ways to create a slice:

  • Index an array or slice with a range, e.g. &array[..] creates a slice of the whole array, whereas &array[2..8] only creates a slice of the 2nd to 7th element of the array.
  • Put an array behind a reference or in a pointer type and then coerce it into a slice. The coercion is possible if the reference or pointer type implements the CoerceUnsizedThis links to official Rust documentation trait.

In addition, Rust provides some built-in functions that build slices unsafely in the core library. Libraries can build slices using those functions, and provide a safe interface:

  • VecThis links to official Rust documentation is a wrapper for dynamically allocated slices. It implements traits like DerefThis links to official Rust documentation and IndexThis links to official Rust documentation , so &Vec<T> can be coerced into &[T], and the type of &vec[2..4] is &[T]. It also provides methods like as_sliceThis links to official Rust documentation.
Because slices are dynamically sized, references to slices are fat — they're twice as big as normal references, because they have to store the slice's memory address as well as their length:
use std::mem::size_of;

type SliceRef = &'static [()];
type ArrayRef = &'static [(); 4];

assert_eq!(size_of::<ArrayRef>(), size_of::<usize>());
assert_eq!(size_of::<SliceRef>(), size_of::<usize>() * 2);

Arrays and const generics

Arrays in Rust have a constant in their type definition. As of Rust 1.51.0, a subset of const generics has been stabilized, so you may create a type that's generic over some integer constants, and use that constant for array size.

struct ArrayWrapper<T, const N: usize> {
    inner: [T; N],
}