Slices
Slice Basics
A slice is a view to a contiguous sequence of elements within a collection (array, vector, etc.).
The slice type is [T]
, where T
represents the element type (e.g. u8
). Because it is dynamically sized, it is most often found behind a pointer:
- Immutable slice reference:
&[T]
, - Mutable slice reference:
&mut [T]
, - Boxed slice (on the heap):
Box<[T]>
, - Shareable reference-counted slice:
Rc<[T]>
orArc<[T]>
.
A few important points:
- Slices do not own the data they point to. This makes them efficient, as they avoid unnecessary copying.
- They allow you to work with parts of a collection, enabling flexibility in data manipulation.
- Slice references are "fat pointers", i.e. they store a pointer and the length of the sequence they refer to, thus they have twice the size of pointers to regular
Sized
types. - As a primitive type,
slice
implements a large number of methods, for example toswap
two elements;reverse
the order of elements in the slice in place;iter
ate elements; createchunks
or overlapping windows into the slice; figure out if the slicecontains
an element with the given value, etc. See also:
Empty slices can be created:
let empty = &x[..0]; // Same as `&x[0..0]`. assert_eq!(empty, &[]);
Common Use Cases
- Accessing Subsets of Data: Slices are frequently used to access specific portions of arrays, vectors, or strings without copying the entire collection.
- Function Arguments: Slices are often used as function arguments when you want to operate on a part of a collection.
- String Manipulation: string slices (
&str
) are a common way to reference a string literal or a portion of aString
(see below).
Create Slices from Arrays or Vectors
Slices can be created by referencing a portion of a collection using a range. The range can be specified using [start..end]
, where start
is the index of the first element to include, and end
is the index of the element after the last one to include. If start
is omitted, the slice starts from the beginning of the collection. If end
is omitted, the slice extends to the end of the collection. [..]
refers to the entire collection.
//! A slice is a view into a contiguous sequence of elements in a collection. //! It does not own the data it points to. /// Create slices from an array: fn slice_from_array() { let array: [i32; 5] = [1, 2, 3, 4, 5]; // Create a slice referencing elements at indices 1, 2, and 3: let slice: &[i32] = &array[1..4]; println!("{slice:?}"); // Output: [2, 3, 4]. // `[..]` refers to the entire collection. let all: &[i32] = &array[..]; println!("Entire array: {all:?}"); // You can also coerce an array to a slice: let arr_slice: &[i32] = &[10, 20]; println!("{arr_slice:?}"); } /// Create slices from a `Vec`: fn slice_from_vector() { let mut vector: Vec<i32> = vec![1, 2, 3, 4, 5]; let slice: &[i32] = &vector[1..4]; // [2, 3, 4]. println!("{slice:?}"); // Mutable slice: let mutable_slice: &mut [i32] = &mut vector[2..]; mutable_slice[0] = 10; // Modifies the original vector. println!("{mutable_slice:?}"); // Output: [1, 2, 10, 4, 5]. } fn main() { slice_from_array(); slice_from_vector(); }
Use a Slice as a Function Argument
You will commonly see slices as function arguments, because Vec<T>
implements Deref<Target = [T]>
. Therefore, you can simply pass a &Vec<T>
to a function that accepts &[T]
:
//! Example of a slice as a function argument. fn sum(slice: &[i32]) -> i32 { let mut sum = 0; // Note: immutable (and mutable) slices implement `IntoIterator`. // The iterator yields references to the slice elements. for &element in slice { sum += element; } sum } fn main() { let vector: Vec<i32> = vec![1, 2, 3, 4, 5]; // `Vec<T>` implements `Deref<Target = [T]>`. // Therefore, you can simply pass a `&Vec` to a function // that accepts `&[T]`. let _ = sum(&vector); let slice: &[i32] = &vector[..]; let _ = sum(slice); }
The example also shows that immutable (and mutable) slices implement IntoIterator
, yielding references to each slice element.
String Slices
String slices, denoted &str
, are very common. In particular, string literals are of type &'static str
. String slices are essentially regular slices, with the additional requirement that they must always be valid UTF-8. Owned strings (String
) dereference to &str
, just like Vec<T>
dereferences to &[T]
.
See the String chapter for more details.