We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Ownership II: Borrowing and the Borrow Checker step 16 of 24
split_at_mut and the disjointness-proof APIs
pub fn fold_halves(xs: &mut [i64]) -> usize
Fold the second half of the slice into the first: add each element of the second half into the matching element of the first half, then zero the second half. Return how many pairs were folded.
The halves are pinned exactly. With n = xs.len() and half = n / 2:
-
the right half is the last
halfelements,xs[n - half ..]; -
the left half is everything before it,
xs[.. n - half]; -
pair
iisxs[i]withxs[n - half + i], in order; -
when
nis odd, the left half is one longer, and its last element — indexhalf, the exact middle — has no partner and is left untouched; -
the return value is
half.
[1,2,3,4] -> 2, [4,6,0,0]
[1,2,3,4,5] -> 2, [5,7,3,0,0] <- index 2 (value 3) is the untouched middle
[10,20,30] -> 1, [40,20,0] <- index 1 (value 20) is the untouched middle
[9] -> 0, [9]
[] -> 0, []
The starter does not compile: E0499, two exclusive loans of the same slice.
The cleanest possible statement of the thesis
You know from item 3.7 that &mut xs[i] and &mut xs[j] cannot coexist,
because both are loans of xs as far as the type system can see, and the
compiler has no theory of arithmetic that would separate them.
Here is the fix, and it is worth staring at:
pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T])
One exclusive reference goes in. Two come out. Both have the same lifetime
as the input. And the whole thing is in core, safe to call, no unsafe at
your call site.
Read what that signature asserts: these two slices do not overlap. The
compiler does not verify that claim from the body — it never reads bodies. It
takes the signature as the contract. Somebody wrote a proof, once, inside
split_at_mut (with unsafe, and a // SAFETY: comment explaining why mid
partitions the buffer), and every caller since has consumed it for free.
So the compiler did not get smarter. Somebody wrote the proof down in a type. That is the single most useful idea in this track, and once you have it, “the borrow checker won’t let me” stops being a dead end and becomes a search query.
Learners who do not have this idea reach for unsafe or RefCell
prematurely, because those are the two escape hatches that are easy to find.
Both are the wrong first move. The right first move is: which standard-library
function already returns the shape I need?
The family
Every one of these has a signature that encodes a disjointness proof. Learn the shapes; you will reach for them constantly.
| function | proof it carries |
|---|---|
split_at_mut(mid) |
two non-overlapping halves |
split_at_mut_checked(mid) |
same, Option instead of a panic (1.80) |
split_first_mut() / split_last_mut() |
one element and the rest |
chunks_mut(n) / chunks_exact_mut(n) |
consecutive non-overlapping blocks |
rchunks_mut(n) |
the same, counted from the end |
iter_mut() |
one element at a time, never revisited (item 3.14) |
get_disjoint_mut([i, j]) |
arbitrary indices, checked at runtime (1.86) |
For this problem, split_at_mut is the obvious fit — but notice that
get_disjoint_mut would also work, one pair at a time, and chunks_mut would
not, because your two halves are not the same length when n is odd.
A word on picking mid. xs.split_at_mut(n - half) puts the middle element
(when there is one) at the end of the left slice, which is exactly what
the spec wants: it never gets a partner. Splitting at half instead would put
the middle at the front of the right slice and fold the wrong pairs. Check
your arithmetic against the odd-length case before you run anything.
Then left.iter_mut().zip(right.iter_mut()) walks the pairs, and zip stops
at the shorter side — which is the right half — so the middle is skipped for
free.
Two lints watching
needless_range_loop if you index; manual_memcpy if you write a loop that
is really a bulk copy (copy_from_slice exists); manual_swap if you write
the three-line temporary-variable exchange rather than slice::swap.
Remember the grade is compile + tests + clippy -D warnings.
Loading visualization…
Stuck?
Rust reference solution
Sign in to attempt this problem and reveal the reference solution.