A slice is a reference to a contiguous part of a collection. Strings are expressed as a slice type called &str, and arrays and vectors are expressed as a slice type called &[T], and in both cases, they operate as a small structure of “pointer length”. As you learn about slicing, function signatures become much more natural.
Learning Objectives
- Understand the difference between
&strandStringand prefer&stras a function parameter. - Some sections of the array/vector are borrowed and processed as
&[T]. - Memorize
[start..end]/[..end]/[start..]/[..]slicing grammar. - Write a function that returns a slice with a pattern such as
first_word.
Key concepts
A slice is a small reference type with two fields: pointer length. Point to the original data rather than copying it.
| Slice Type | Pointing to original |
|---|---|
&str |
String, &'static str (string literal) |
&[T] |
[T; N] array, Vec<T>, or another slice |
let s = String::from("hello world");
&s[0..5]; // "hello"
&s[6..]; // "world"
&s[..]; //All
let a = [10, 20, 30, 40];
&a[1..3]; // [20, 30]
In a string slice, the range is in bytes. If you truncate outside of a UTF-8 character boundary, a runtime panic occurs.
When a function receives a slice type, the caller can pass String, an array, or a vector as is, providing good compatibility.
| parameters | Compatible Calls |
|---|---|
&str |
&String, &'static str("...") |
&[T] |
&[T; N], &Vec<T> |
fn first_word(s: &str) -> &str {
for (i, &b) in s.as_bytes().iter().enumerate() {
if b == b' ' { return &s[..i]; }
}
s
}
The returned &str points to a portion of the input s. Lifetime is automatically inferred from the input (more details in the next part, Lesson 9).
See as example
//Part 8 Example 1: String Slice
//
//A type that borrows part of String
//The string literal "abc" is actually
fn main() {
let s = String::from("Hello, World!");
//The range is [start..end). Except the end.
let hello: &str = &s[0..5];
let world: &str = &s[7..12];
let all: &str = &s[..]; //All
println!("hello = {hello}");
println!("world = {world}");
println!("all = {all}");
//
print_len("Rust");
print_len(&s);
}
fn print_len(s: &str) {
println!("Byte length of \"{s}\": {}", s.len());
}
//Part 8 Example 2: Array/Vector Slice
//
//A type that borrows consecutive parts of an array or vector
fn sum(nums: &[i32]) -> i32 {
let mut total = 0;
for n in nums {
total += n;
}
total
}
fn main() {
let arr = [10, 20, 30, 40, 50];
let vec = vec![1, 2, 3, 4, 5];
//Borrowing the entire array/vector as a slice
println!("Total array sum = {}", sum(&arr));
println!("vector total sum = {}", sum(&vec));
//Rent a section
let mid: &[i32] = &arr[1..4]; // 20, 30, 40
println!("arr[1..4] = {:?}, sum = {}", mid, sum(mid));
}
//Part 8 Example 3: first_word — A classic example of a slice
//
//Returns the slice up to the first space in a string.
//Slice is safer than returning only the index (usize).
fn first_word(s: &str) -> &str {
for (i, &b) in s.as_bytes().iter().enumerate() {
if b == b' ' {
return &s[..i];
}
}
s
}
fn main() {
let sentence = String::from("Rust is a system language");
let word = first_word(&sentence);
println!("First word: {word}");
//Can also be applied to string literals
let lit = "Hello World";
println!("First Word (lit): {}", first_word(lit));
}
Common Mistakes
A. String slicing is byte-by-byte. UTF-8 If you truncate a character in the middle, it will panic. To handle it safely, you need to find the character boundary with s.char_indices() and then cut it (this will be covered in depth in Part 10 of the next part).
A. The borrowing rules prevent that. If you try to modify s while &s[0..5] is alive, you will get a compile error — "cannot borrow as mutable".
A. It is almost always &[T]. The caller can call it from any array, vector, or other slice, and library compatibility is good.
A: Yes. &mut [T] is a mutable slice whose slice elements can be modified. Example: arr.sort() internally uses &mut [T].
Cleanup
- A slice
&str/&[T]is a small reference to a part of a collection. - Slicing grammar is
[start..end],[..end],[start..],[..]. - It is more common to receive function parameters as
&strinstead ofStringand&[T]instead ofVec<T>. - String slicing is byte-by-byte — panic when cutting in the middle of a multibyte character.
Try it yourself
Solve the assignment below. The reference solution is shown below.