Vec<T> in Depth
Borrowing Vector Elements
Borrowing elements from a Vec<T> creates references (&T, &mut T, &[T], or &mut [T]) pointing directly into the vector's heap buffer, tying the lifetime of those element references to the borrow of the Vec<T> itself.
Shared vs. Mutable Element Borrows
| Borrow Expression | Returned Type | Concurrent Operations Allowed on v |
|---|---|---|
&v[i] / v.get(i) / v.first() |
&T / Option<&T> |
Other shared reads (&v[j], v.len(), v.iter()); no mutation of v |
&mut v[i] / v.get_mut(i) |
&mut T / Option<&mut T> |
None while the &mut T reference is live |
&v[a..b] / v.as_slice() |
&[T] |
Other shared reads; no mutation of v |
&mut v[a..b] / v.as_mut_slice() |
&mut [T] |
None while the &mut [T] slice is live |
Why You Cannot Index Two Mutable Elements Directly (E0499)
Because the IndexMut trait signature is fn index_mut(&mut self, index: Idx) -> &mut Self::Output, borrowing &mut v[0] exclusively borrows the entire v: Vec<T> for as long as that reference is live. Attempting to borrow &mut v[1] at the same time via a second index_mut call fails with E0499:
// ❌ does not compile
fn main() {
let mut v = vec![10, 20, 30];
let a = &mut v[0];
let b = &mut v[1];
*a += *b;
}
error[E0499]: cannot borrow `v` as mutable more than once at a time
--> src/main.rs:5:18
|
4 | let a = &mut v[0];
| - first mutable borrow occurs here
5 | let b = &mut v[1];
| ^ second mutable borrow occurs here
6 | *a += *b;
| -------- first borrow later used here
|
= help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices
Safe Ways to Borrow Multiple Vector Elements Mutably
Rust provides four safe mechanisms that prove to the compiler that multiple mutable element references do not overlap:
v.get_disjoint_mut([i, j]): ReturnsOk([&mut T; N])for any $N$ distinct runtime indices.- Slice pattern destructuring (
if let [a, b, ..] = &mut v[..]): Binds disjoint mutable references at fixed positions. v.split_at_mut(mid)/v.split_first_mut(): Splits&mut [T]into two non-overlapping mutable slices.v.swap(i, j): Swaps two elements in place when you only need to exchange their positions.
fn main() {
let mut matrix_row = vec![1, 2, 3, 4];
// 1. Disjoint mutable references by runtime indices:
if let Ok([first, last]) = matrix_row.get_disjoint_mut([0, 3]) {
*first *= 10;
*last *= 10;
}
// 2. Swapping two elements directly:
matrix_row.swap(1, 2);
println!("Updated row: {matrix_row:?}");
}
Updated row: [10, 3, 2, 40]