Vec<T> in Depth

Indexing and get()

Vec<T> (and [T]) supports two styles of element and range access: direct indexing (v[index]), which panics on out-of-bounds indices, and checked indexing (v.get(index) / v.get_mut(index)), which returns Option<&T> or Option<&mut T> without panicking.

Comparing v[i] vs. v.get(i)

Expression Return Type (Single Index usize) Return Type (Range a..b) Out-of-Bounds Behavior
&v[index] &T &[T] Panics at runtime
&mut v[index] &mut T &mut [T] Panics at runtime
v.get(index) Option<&T> Option<&[T]> Returns None
v.get_mut(index) Option<&mut T> Option<&mut [T]> Returns None

Single-Element and Range Indexing

Both [index] and .get(index) accept any type implementing std::slice::SliceIndex<[T]>, including a single usize or any range type (a..b, a..=b, ..b, a.., ..):

fn main() {
    let mut readings = vec![100, 200, 300, 400];

    // 1. Direct indexing (when index is known to be in bounds):
    readings[1] = 250;
    println!("Element 1: {}", readings[1]);
    println!("Slice 1..3: {:?}", &readings[1..3]);

    // 2. Checked indexing with `.get()` and `.get_mut()`:
    println!("get(2):     {:?}", readings.get(2));
    println!("get(99):    {:?}", readings.get(99));
    println!("get(2..10): {:?}", readings.get(2..10));

    if let Some(slot) = readings.get_mut(3) {
        *slot += 50;
    }
    println!("After get_mut(3): {readings:?}");
}
Element 1: 250
Slice 1..3: [250, 300]
get(2):     Some(300)
get(99):    None
get(2..10): None
After get_mut(3): [100, 250, 300, 450]

Disjoint Multi-Element Mutable Access with get_disjoint_mut

When you need mutable references to two or more distinct indices simultaneously (&mut v[i] and &mut v[j]), v.get_disjoint_mut([i, j]) (stabilized in Rust 1.86) checks that all indices are in bounds and pairwise distinct, returning Result<[&mut T; N], GetDisjointMutError>:

fn main() {
    let mut accounts = vec![1_000_i64, 500, 2_000];

    // Borrow indices 0 and 2 mutably at the same time:
    if let Ok([from, to]) = accounts.get_disjoint_mut([0, 2]) {
        *from -= 300;
        *to += 300;
    }

    println!("Accounts after transfer: {accounts:?}");
    println!(
        "Overlapping indices [1, 1]: {:?}",
        accounts.get_disjoint_mut([1, 1])
    );
}
Accounts after transfer: [700, 500, 2300]
Overlapping indices [1, 1]: Err(OverlappingIndices)

When to Use v[i] vs. v.get(i)

  • Use v.get(i) whenever i comes from external input, user arguments, or arithmetic that might exceed v.len(), or when None naturally drives control flow (if let Some(x) = v.get(i)).
  • Use v[i] when an out-of-bounds index represents an internal logic bug in your algorithm and panicking immediately is the intended invariant check.