Slices in Rust are references to a contiguous segment of elements in a collection, such as an array or a string.
They allow you to work with a subset of data without copying it.
Slices are powerful and ensure safety by preventing out-of-bounds access.
What You’ll Learn
1. What Are Slices?
A slice in Rust is a dynamically-sized reference to part of a collection. It is created by borrowing a portion of a collection, and its type is &[T] for an array slice or &str for a string slice.
Example: Array Slices
fn main() { let arr = [1, 2, 3, 4, 5]; let slice = &arr[1..4]; // Borrow elements 1 through 3 (exclusive of 4) println!("Slice: {:?}", slice); // Output: [2, 3, 4] }
2. Working with Array Slices
You can create slices from arrays using a range.
Example: Basic Array Slices
fn main() { let arr = [10, 20, 30, 40, 50]; let full_slice = &arr[..]; // Slice the entire array let part_slice = &arr[1..4]; // Slice from index 1 to 3 println!("Full slice: {:?}", full_slice); println!("Part slice: {:?}", part_slice); }
Example: Accessing Slice Elements
fn main() { let arr = [1, 2, 3, 4, 5]; let slice = &arr[2..]; // Slice from index 2 to the end println!("First element: {}", slice[0]); // Accessing elements println!("Slice length: {}", slice.len()); }
3. String Slices
String slices (&str) are references to a part of a String or string literal.
Example: Slicing Strings
fn main() { let s = String::from("Hello, Rust!"); let slice = &s[0..5]; // Slice the first 5 characters println!("Slice: {}", slice); // Output: Hello }
Example: String Literals as Slices
String literals (“Hello”) are inherently string slices (&str).
fn main() { let literal: &str = "Rust"; println!("String slice: {}", literal); }
4. Slices and Iteration
Slices can be easily iterated using loops.
Example: Iterating Over an Array Slice
fn main() { let arr = [10, 20, 30, 40, 50]; let slice = &arr[1..4]; for &item in slice { println!("Item: {}", item); } }
Example: Iterating Over a String Slice
fn main() { let s = "Rust"; for c in s.chars() { println!("{}", c); } }
5. Slices as Function Parameters
Slices are often used as function parameters to allow borrowing part of an array or string.
Example: Function with Array Slice Parameter
fn sum(slice: &[i32]) -> i32 { slice.iter().sum() } fn main() { let arr = [1, 2, 3, 4, 5]; let slice = &arr[1..4]; // Borrow part of the array println!("Sum: {}", sum(slice)); // Output: 9 }
Example: Function with String Slice Parameter
fn print_slice(slice: &str) { println!("Slice: {}", slice); } fn main() { let s = String::from("Hello, Rust!"); print_slice(&s[0..5]); // Pass a slice of the string }
6. Mutable Slices
Mutable slices allow modifying the elements of the original collection.
Example: Modifying Elements
fn main() { let mut arr = [1, 2, 3, 4, 5]; let slice = &mut arr[1..4]; // Mutable slice for elem in slice.iter_mut() { *elem *= 2; // Double each element } println!("Modified array: {:?}", arr); // Output: [1, 4, 6, 8, 5] }
7. Slices with Ranges
Slices are commonly created using range syntax.
Example: Range Syntax
fn main() { let arr = [10, 20, 30, 40, 50]; let slice1 = &arr[..]; // Entire array let slice2 = &arr[..3]; // From start to index 2 let slice3 = &arr[2..]; // From index 2 to the end let slice4 = &arr[1..4]; // From index 1 to 3 println!("slice1: {:?}", slice1); println!("slice2: {:?}", slice2); println!("slice3: {:?}", slice3); println!("slice4: {:?}", slice4); }
8. Practical Examples
8.1 Finding the Maximum Value in a Slice
fn find_max(slice: &[i32]) -> i32 { *slice.iter().max().unwrap() } fn main() { let arr = [3, 7, 2, 8, 4]; let slice = &arr[1..4]; // Borrow part of the array println!("Max value: {}", find_max(slice)); // Output: 8 }
8.2 Splitting a String
fn main() { let sentence = "Rust is amazing!"; let words: Vec<&str> = sentence.split_whitespace().collect(); for word in words { println!("{}", word); } }
8.3 Reversing a Slice
fn reverse_slice(slice: &mut [i32]) { slice.reverse(); } fn main() { let mut arr = [1, 2, 3, 4, 5]; reverse_slice(&mut arr[1..4]); // Reverse part of the array println!("Reversed array: {:?}", arr); // Output: [1, 4, 3, 2, 5] }
8.4 String Substring Search
fn contains_word(sentence: &str, word: &str) -> bool { sentence.contains(word) } fn main() { let text = "Rust is fast and safe!"; println!("Contains 'fast': {}", contains_word(text, "fast")); // Output: true }
9. Summary
Key Features
- Slices are references to parts of arrays or strings.
- Array slices have the type &[T].
- String slices have the type &str.
- Slices are used for borrowing data without copying.
- They ensure safety by preventing out-of-bounds access.
Common Use Cases
- Working with parts of arrays or strings.
- Passing data to functions without ownership transfer.
- Iterating over collections safely.
Rust slices are a fundamental feature for safe and efficient programming.