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:

  1. v.get_disjoint_mut([i, j]): Returns Ok([&mut T; N]) for any $N$ distinct runtime indices.
  2. Slice pattern destructuring (if let [a, b, ..] = &mut v[..]): Binds disjoint mutable references at fixed positions.
  3. v.split_at_mut(mid) / v.split_first_mut(): Splits &mut [T] into two non-overlapping mutable slices.
  4. 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]