Arrays and Slices
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];
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 Box
. 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
CoerceUnsized
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:
Vec
is a wrapper for dynamically allocated slices. It implements traits likeDeref
andIndex
, so&Vec<T>
can be coerced into&[T]
, and the type of&vec[2..4]
is&[T]
. It also provides methods likeas_slice
.
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],
}