Need a &mut to two different elements of the same slice at once? Indexing twice won’t compile — the borrow checker sees the whole slice borrowed twice. split_at_mut hands you two non-overlapping mutable halves instead.
The borrow checker says no
You want to mutate two elements of a slice in the same expression — say, swap-style logic that reads one and writes another:
1
2
3
4
| let mut v = [1, 2, 3, 4];
let a = &mut v[0];
let b = &mut v[3]; // error: cannot borrow `v` as mutable more than once
*a += *b;
|
The compiler can’t prove v[0] and v[3] are different elements, so it rejects two overlapping &mut borrows of v. Both indexing operations borrow the entire slice.
split_at_mut gives you two disjoint slices
split_at_mut(mid) splits a slice into [0, mid) and [mid, len), returning a &mut to each. Because the halves provably don’t overlap, the borrow checker is happy:
1
2
3
4
| let mut v = [1, 2, 3, 4];
let (left, right) = v.split_at_mut(2);
left[0] += right[1]; // v[0] += v[3]
assert_eq!(v, [5, 2, 3, 4]);
|
Internally it’s one bounds check and a pointer offset — no copying, no allocation. It panics only if mid > len; use split_at_mut_checked to get an Option instead.
Where it shines: in-place algorithms
Reversing a slice by hand needs a read and a write to two indices each step. Split once, walk inward:
1
2
3
4
5
6
7
8
9
10
11
| fn reverse<T>(s: &mut [T]) {
let n = s.len();
let (front, back) = s.split_at_mut(n / 2);
for (a, b) in front.iter_mut().zip(back.iter_mut().rev()) {
std::mem::swap(a, b);
}
}
let mut data = [1, 2, 3, 4, 5];
reverse(&mut data);
assert_eq!(data, [5, 4, 3, 2, 1]);
|
The two iterators borrow disjoint halves, so iterating both mutably at once just works.
Divide and conquer for free
Because each half is itself a &mut [T], recursive algorithms split cleanly — the basis for parallelizing with something like Rayon’s join:
1
2
3
4
5
6
7
8
9
10
11
| fn sum_halves(s: &mut [i32]) -> i32 {
if s.len() <= 1 {
return s.first().copied().unwrap_or(0);
}
let mid = s.len() / 2;
let (left, right) = s.split_at_mut(mid);
sum_halves(left) + sum_halves(right)
}
let mut v = [1, 2, 3, 4, 5];
assert_eq!(sum_halves(&mut v), 15);
|
Whenever you’re fighting the borrow checker over two mutable spots in one slice, stop reaching for unsafe — split_at_mut is the safe, zero-cost answer. For non-adjacent individual elements, its cousin get_disjoint_mut does the same trick by index.