We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Ownership II: Borrowing and the Borrow Checker step 2 of 24
&mut: exclusive access, and why `mut` appears twice
Three small in-place edits, applied in this order:
pub fn double_all(xs: &mut [i64])
pub fn clamp_all(xs: &mut [i64], lo: i64, hi: i64)
pub fn drop_zeros(xs: &mut Vec<i64>)
-
double_allmultiplies every element by 2. -
clamp_allpulls every element into the rangelo..=hi. You may assumelo <= hi. -
drop_zerosremoves every element that is exactly0, keeping the order of the rest.
So [1, -3, 7] with lo = -4, hi = 6 doubles to [2, -6, 14], clamps to
[2, -4, 6], and loses no zeros. [0, 5] with a wide range doubles to
[0, 10], clamps to itself, and becomes [10].
double_all and clamp_all are already written for you as todo!().
drop_zeros is written wrongly for you, and it does not compile. Fixing it
is the first half of the exercise.
&mut means exclusive, not “mutable”
&T lets you read. &mut T lets you read and write. That much is obvious
from the name. What the name hides is the more important half of the deal:
While a
&mut Texists, it is the only way to reach that value. Not the only way to write it — the only way to reach it at all. Not even the owner may read it.
That is why experienced Rust programmers say “exclusive reference” rather than “mutable reference”. Mutability is what you get; exclusivity is what you pay. Every borrow error in this track is a consequence of that one sentence, so it is worth reading twice.
Why mut appears twice, and which one you usually forgot
This is the single most common week-one confusion, so let us be blunt about
it. mut is two unrelated things that share a keyword.
let mut v = vec![1, 2, 3]; // (1) this binding may be reassigned/mutated
let r: &mut Vec<i64> = &mut v; // (2) this reference grants write access
-
let mut vis a property of the variable. Without it,vis a read-only binding and you may not create a&mutto it. -
&mut vis a property of the reference. It is the loan itself.
You cannot have (2) without (1). And when you forget (1), the error you get talks about (2):
error[E0596]: cannot borrow `keep` as mutable, as it is not declared as mutable
Beginners read that, look at the &-free line it points to, and have no idea
what to add. The fix is never on the line the error points at — it is on the
let. Add mut there. The starter code contains exactly this bug, and it is
worth meeting it once on purpose rather than at 1am.
&mut [i64] versus &mut Vec<i64>
Look at the three signatures again. The first two take &mut [i64], a mutable
slice. The third takes &mut Vec<i64>. That is not stylistic noise:
-
A slice is a view of some contiguous elements. Through
&mut [i64]you may change any element you like, but you may never change how many there are. The length is part of the view, fixed when the view was made. -
A
Vecowns its buffer. Only through&mut Vec<i64>can youpush,remove,retain,clear— anything that resizes.
double_all and clamp_all only edit elements, so they ask for the weaker,
more general thing. drop_zeros genuinely removes elements, so it must ask
for the Vec.
Take the weakest parameter type that does the job. It is not politeness; it
is what makes your function callable from more places. Clippy enforces this
direction too — write &mut Vec<i64> for a function that only edits elements
and ptr_arg will reject it under -D warnings. Try it if you want to see it
fire.
Notice the harness never has to care: it holds a Vec<i64> and writes
double_all(&mut xs). Rust turns &mut Vec<i64> into &mut [i64]
automatically at the call site. That is deref coercion, and item 3.10 is
about it.
Hints toward good style
Writing for i in 0..xs.len() { xs[i] = ... } will compile, and clippy will
reject it (needless_range_loop). The idiomatic way to walk a slice and write
to it is for x in xs.iter_mut(), which hands you a &mut i64 per element.
Then *x is the element. Item 3.14 explains why that is sound; for now, use
it.
For drop_zeros, the standard library already has the operation. Look for the
Vec method that keeps only the elements matching a predicate — clippy will
name it for you if you write the loop by hand.
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.