Slices
What Is a Slice?
Section titled “What Is a Slice?”A slice is a reference to a contiguous sequence of elements in a collection. It does not own the data — it borrows a view into existing memory.
There are two common slice types:
&[T]— a slice of any array or vector of typeT&str— a string slice; a view into UTF-8 string data
Because a slice is always a reference, its lifetime is tied to the collection it borrows from.
Array and Vector Slices
Section titled “Array and Vector Slices”Given an array or vector, you create a slice using range syntax inside square brackets:
fn main() { let numbers = [10, 20, 30, 40, 50];
let all: &[i32] = &numbers[..]; // entire array let first_three: &[i32] = &numbers[..3]; // indices 0, 1, 2 let middle: &[i32] = &numbers[1..4]; // indices 1, 2, 3 let last_two: &[i32] = &numbers[3..];// indices 3, 4
println!("all: {:?}", all); println!("first three: {:?}", first_three); println!("middle: {:?}", middle); println!("last two: {:?}", last_two);}Range syntax summary:
| Syntax | Meaning |
|---|---|
[..] | entire collection |
[..n] | first n elements (indices 0 to n-1) |
[m..n] | indices m to n-1 |
[m..] | from index m to the end |
String Slices (&str)
Section titled “String Slices (&str)”A string slice (&str) is a reference to a portion of a String or a string literal. String literals themselves are &str — they are slices of read-only data baked into the binary.
fn main() { let s = String::from("hello world");
let hello: &str = &s[..5]; // "hello" let world: &str = &s[6..]; // "world"
println!("{} {}", hello, world);
// A string literal is already &str let literal: &str = "Rust is fast"; println!("{}", literal);}Slices Prevent Dangling Indices
Section titled “Slices Prevent Dangling Indices”Without slices, you might store an index into a string and then modify the string — leaving the index pointing to meaningless data. With a string slice, the borrow checker ensures the slice cannot outlive the data it references.
fn first_word(s: &str) -> &str { let bytes = s.as_bytes(); for (i, &byte) in bytes.iter().enumerate() { if byte == b' ' { return &s[..i]; // slice up to the space } } s // whole string is one word}
fn main() { let sentence = String::from("hello world"); let word = first_word(&sentence); // sentence cannot be mutated while word (a slice of it) is alive println!("first word: {}", word);}Slices as Function Parameters
Section titled “Slices as Function Parameters”Functions that operate on sequences should accept slices rather than owned types. This lets them work with arrays, vectors, and any portion thereof without requiring ownership.
- Prefer
&[T]over&Vec<T>for sequence parameters - Prefer
&strover&Stringfor string parameters
Both &Vec<T> and &String coerce automatically to their slice equivalents at call sites.
fn first_word(s: &str) -> &str { let bytes = s.as_bytes(); for (i, &byte) in bytes.iter().enumerate() { if byte == b' ' { return &s[..i]; } } s}
fn sum_slice(nums: &[i32]) -> i32 { let mut total = 0; for &n in nums { total += n; } total}
fn main() { // String slice let sentence = String::from("hello world"); let word = first_word(&sentence); println!("first word: {}", word);
// Integer slice let numbers = [10, 20, 30, 40, 50]; let middle: &[i32] = &numbers[1..4]; println!("middle slice: {:?}", middle); println!("sum of middle: {}", sum_slice(middle));
// String slice literal let greeting: &str = "Rust is safe"; println!("slice: {}", &greeting[..4]);}Compiling…