Standard Collections
Borrowing Collection Elements
The borrow checker tracks a collection as a single ownership unit: borrowing a single element (&vec[0] or map.get(&k)) borrows the entire collection for the lifetime of that element reference.
Why Borrowing One Element Locks the Collection Against Mutation (E0502)
If you hold a shared reference let first = &vec[0]; and then call vec.push(x), push might exceed vec.capacity(), allocate a new heap buffer, copy the elements over, and free the old buffer—leaving first as a dangling pointer! Rust prevents this at compile time:
first = &vec[0] ──────┐
▼
Old Heap Buffer: [ 10, 20 ] <-- If `vec.push(30)` reallocated and freed this,
`first` would dangle!
// ❌ does not compile
fn main() {
let mut vec = vec![10, 20];
let first = &vec[0]; // Immutable borrow of `vec` starts here
vec.push(30); // Error: mutable borrow of `vec` while `first` is still live
println!("First: {first}");
}
error[E0502]: cannot borrow `vec` as mutable because it is also borrowed as immutable
--> src/main.rs:6:5
|
4 | let first = &vec[0];
| --- immutable borrow occurs here
5 |
6 | vec.push(30);
| ^^^^^^^^^^^^ mutable borrow occurs here
7 |
8 | println!("First: {first}");
| ------- immutable borrow later used here
Borrowing Multiple Elements Mutably at the Same Time
Because the compiler's index operator (&mut vec[0] and &mut vec[1]) cannot prove in general that two runtime index expressions i and j are distinct, attempting to take two &mut element references via indexing fails with E0499.
Instead, use dedicated disjoint-borrowing methods on slices and maps:
| Method | Signature / Target | What It Provides |
|---|---|---|
slice.split_at_mut(mid) |
&mut [T] |
Two non-overlapping mutable slices (&mut [T], &mut [T]) (..mid and mid..) |
slice.split_first_mut() |
&mut [T] |
Option<(&mut T, &mut [T])> (first element + remaining tail) |
[a, b] slice pattern |
if let [first, second, ..] = &mut slice[..] |
Disjoint mutable bindings via slice pattern matching |
slice.swap(i, j) |
&mut [T] |
Swaps two elements in place without holding two &mut references |
fn main() {
let mut scores = vec![100, 200, 300, 400];
// 1. Disjoint mutable borrows via slice pattern matching:
if let [first, second, ..] = &mut scores[..] {
*first += 10;
*second += 20;
}
// 2. Splitting into two non-overlapping mutable halves with `split_at_mut`:
let (left, right) = scores.split_at_mut(2);
left[0] += right[0];
println!("Updated scores: {scores:?}");
}
Updated scores: [410, 220, 300, 400]