Array Slices
An array slice (&[T] or &mut [T]) is a dynamically sized view into a contiguous sequence of elements of type T inside an array ([T; N]), vector (Vec<T>), or another slice. While an array type [T; N] bakes its compile-time length N into the type itself, an array slice &[T] erases the compile-time length N and carries its length at runtime inside a 16-byte fat pointer (ptr + len).
Fixed-Size Array ([T; N]) vs Array Slice (&[T])
| Property | Fixed-Size Array [T; N] (or &[T; N]) |
Array Slice &[T] / &mut [T] |
|---|---|---|
| Owns the elements? | [T; N] owns elements; &[T; N] borrows all N elements |
Borrows a contiguous range of elements |
| Length known at | Compile time (N is part of the type) |
Runtime (slice.len() stored in fat pointer) |
| Pointer size (64-bit) | &[T; N] is 8 bytes (thin pointer—length is known from N) |
&[T] is 16 bytes (8-byte ptr + 8-byte len) |
| Can point to a sub-range? | No (always refers to the entire N-element array) |
Yes (&arr[start..end] can view any contiguous sub-range) |
| Accepts arrays of different lengths? | No (&[i32; 3] rejects &[i32; 5]) |
Yes (accepts &[i32; 3], &[i32; 5], and &Vec<i32>) |
Stack Array (`arr: [i32; 5]`):
+-----+-----+-----+-----+-----+
| 100 | 200 | 300 | 400 | 500 |
+-----+-----+-----+-----+-----+
[0] [1] [2] [3] [4]
^ ^
│ │
`let sub: &[i32] = &arr[1..=3];` --> `ptr` points to `arr[1]`, `len = 3` (`[200, 300, 400]`)
Creating Array Slices via Unsized Coercion and Range Indexing
There are two ways to obtain an array slice &[T] or &mut [T] from an array:
- Whole-array unsized coercion (
&arror&mut arr): When you assign&arrto a variable or parameter of type&[T](or callarr.as_slice()/arr.as_mut_slice()), Rust automatically converts the thin array reference&[T; N]into a fat slice reference&[T]withlen = N. - Range indexing (
&arr[range]or&mut arr[range]): Indexing an array with any range operator (start..end,start..=end,..end,start..,..) produces a slice covering that sub-range.
fn print_slice(label: &str, slice: &[i32]) {
println!("{label:<16} (len {}): {slice:?}", slice.len());
}
fn main() {
let numbers: [i32; 6] = [10, 20, 30, 40, 50, 60];
// 1. Implicit unsized coercion from `&[i32; 6]` to `&[i32]`:
print_slice("Full (&numbers)", &numbers);
// 2. Range slicing into sub-arrays:
print_slice("&numbers[1..4]", &numbers[1..4]);
print_slice("&numbers[..3]", &numbers[..3]);
print_slice("&numbers[4..]", &numbers[4..]);
print_slice("Empty [2..2]", &numbers[2..2]);
}
Full (&numbers) (len 6): [10, 20, 30, 40, 50, 60]
&numbers[1..4] (len 3): [20, 30, 40]
&numbers[..3] (len 3): [10, 20, 30]
&numbers[4..] (len 2): [50, 60]
Empty [2..2] (len 0): []
Splitting and Chunking Array Slices
Because creating sub-slices only computes a new (ptr, len) pair without copying elements, standard slice methods let you partition an array into non-overlapping or overlapping sub-slices in $O(1)$ time per step:
fn main() {
let mut data: [i32; 6] = [1, 2, 3, 4, 5, 6];
// `split_at_mut(mid)` safely splits one `&mut [i32]` into TWO disjoint mutable slices!
let (left, right) = data.split_at_mut(3);
left[0] = 100;
right[0] = 400;
println!("After split_at_mut(3): {data:?}");
// Iterate over fixed-size non-overlapping chunks of 2 elements:
for (idx, pair) in data.chunks(2).enumerate() {
println!(" Chunk {idx}: {pair:?}");
}
}
After split_at_mut(3): [100, 2, 3, 400, 5, 6]
Chunk 0: [100, 2]
Chunk 1: [3, 400]
Chunk 2: [5, 6]
Converting an Array Slice Back to a Fixed-Size Array (TryFrom)
When you have a slice &[T] whose length is only known at runtime, and you need a fixed-size array [T; N] (or &[T; N]), use TryFrom / .try_into(). The conversion checks slice.len() == N at runtime and returns Ok([T; N]) if the length matches, or Err(TryFromSliceError) if not:
fn parse_ipv4_header(packet: &[u8]) -> Option<[u8; 4]> {
// Extract the first 4 bytes as `&[u8]` and convert to `[u8; 4]`:
let first_four: &[u8] = packet.get(0..4)?;
first_four.try_into().ok()
}
fn main() {
let raw_bytes: &[u8] = &[192, 168, 1, 1, 80, 90];
let short_bytes: &[u8] = &[127, 0];
println!("Valid 4-byte array: {:?}", parse_ipv4_header(raw_bytes));
println!("Too short slice: {:?}", parse_ipv4_header(short_bytes));
}
Valid 4-byte array: Some([192, 168, 1, 1])
Too short slice: None