Slices

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
  |                          +