Skip to content

← Ownership II: Borrowing and the Borrow Checker step 2 of 24

Easy Primitives

&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_all multiplies every element by 2.
  • clamp_all pulls every element into the range lo..=hi. You may assume lo <= hi.
  • drop_zeros removes every element that is exactly 0, 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 T exists, 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
  1. let mut v is a property of the variable. Without it, v is a read-only binding and you may not create a &mut to it.
  2. &mut v is 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 Vec owns its buffer. Only through &mut Vec<i64> can you push, 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…