Common Slice Errors
Compile-time and runtime errors involving slices typically fall into four categories: using bare unsized [T] or str without indirection, simultaneously borrowing two elements mutably via indexing, mutating a container while holding a slice into it, and slicing &str across multi-byte UTF-8 characters.
Summary of Common Slice Pitfalls
| Error / Issue | Compiler Code or Runtime Symptom | Root Cause | Idiomatic Fix |
|---|---|---|---|
Bare [T] or str by value |
E0277 (doesn't have a size known at compile-time) |
Using [T] or str without &, &mut, or Box |
Use &[T], &mut [T], &str, or Box<[T]> |
Two mutable borrows of the same slice via s[i] and s[j] |
E0499 (cannot borrow *s as mutable more than once) |
The borrow checker treats s[i] as borrowing the entire slice s |
Use s.split_at_mut(mid), s.swap(i, j), or [a, .., b] slice patterns |
Modifying a Vec<T> or String while a slice is live |
E0502 (cannot borrow as mutable because it is also borrowed as immutable) |
Appending to a Vec can reallocate and invalidate the slice's ptr |
Finish using the slice before mutating, or store integer indices (usize) |
Slicing &str by character count instead of byte offset |
Runtime panic (byte index N is not a char boundary) |
Assuming 1 character == 1 byte in UTF-8 | Use .char_indices(), .chars().take(n), or .get(range) |
Error 1: Borrowing Two Mutable Elements Simultaneously (E0499)
Because the compiler cannot prove in general that runtime indices i and j are distinct (i != j), taking &mut slice[0] and &mut slice[1] in the same scope fails with E0499:
// ❌ does not compile
fn main() {
let mut data = [10, 20, 30, 40];
let s: &mut [i32] = &mut data;
let first = &mut s[0];
let second = &mut s[1];
*first += *second;
}
error[E0499]: cannot borrow `*s` as mutable more than once at a time
--> src/main.rs:6:22
|
5 | let first = &mut s[0];
| ---- first mutable borrow occurs here
6 | let second = &mut s[1];
| ^^^^ second mutable borrow occurs here
7 | *first += *second;
| ----------------- first borrow later used here
|
= help: consider using `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices
Fix: Use split_at_mut, swap, or Mutable Slice Patterns
fn main() {
let mut data = [10, 20, 30, 40];
let s: &mut [i32] = &mut data;
// Option A: Mutable slice pattern for fixed positions
if let [first, second, ..] = s {
*first += *second;
}
// Option B: `split_at_mut(mid)` for arbitrary runtime index `mid`
let (left, right) = s.split_at_mut(2);
left[0] += right[1];
println!("Result: {s:?}");
}
Result: [70, 20, 30, 40]
Error 2: Mutating a Collection While Holding a Slice (E0502)
Holding a slice (&[T] or &str) into a Vec<T> or String borrows the entire container. Pushing to or clearing the container while the slice is still in use is rejected because reallocation would leave the slice dangling:
// ❌ does not compile
fn main() {
let mut words = String::from("hello world");
let first_word: &str = &words[..5];
words.push_str("!"); // Error: cannot mutate `words` while `first_word` is live
println!("First word: {first_word}");
}
error[E0502]: cannot borrow `words` as mutable because it is also borrowed as immutable
--> src/main.rs:5:5
|
3 | let first_word: &str = &words[..5];
| ----- immutable borrow occurs here
4 |
5 | words.push_str("!"); // Error: cannot mutate `words` while `first_word` is live
| ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
6 | println!("First word: {first_word}");
| ---------- immutable borrow later used here
Fix: Complete the Read Before Mutating or Store a Range 0..5
fn main() {
let mut words = String::from("hello world");
let first_range = 0..5; // Store an index range (`Range<usize>`) instead of a borrow
words.push_str("!");
println!("First word: {}", &words[first_range]);
}
First word: hello
Error 3: Moving Out of a Slice of Non-Copy Elements (E0508)
Because a slice &[T] does not own its elements, indexing slice[i] by value is only allowed when T: Copy. If T does not implement Copy (for example, String), you must borrow &slice[i] or clone slice[i].clone():
// ❌ does not compile
fn main() {
let names = [String::from("Ada"), String::from("Grace")];
let slice: &[String] = &names;
let first: String = slice[0]; // Cannot move `String` out of borrowed slice
println!("{first}");
}
error[E0508]: cannot move out of type `[String]`, a non-copy slice
--> src/main.rs:5:25
|
5 | let first: String = slice[0]; // Cannot move `String` out of borrowed slice
| ^^^^^^^^
| |
| cannot move out of here
| move occurs because `slice[_]` has type `String`, which does not implement the `Copy` trait
|
help: consider borrowing here
|
5 | let first: &String = &slice[0]; // Cannot move `String` out of borrowed slice
| +