We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Ownership II: Borrowing and the Borrow Checker step 17 of 24
Reborrowing: why &mut sometimes moves and sometimes doesn't
Repair two functions that reuse mutable references. Keep consume unchanged:
fn consume<T>(t: T) -> T { t }
pub fn tally(slots: &mut [i64], ops: &[i64]) -> i64
pub fn nudge(slot: Option<&mut i64>, d: i64) -> i64
Required behavior
tally processes operations in order. Operation i targets
slots[i % slots.len()]: add the operation's value, then replace a negative
result with 0. For each operation, pass a mutable reference through
consume twice: once for the addition and once for the clamp to zero.
Return the sum of all slots after processing the operations.
Empty slots return 0 without processing operations. Slots that receive no
operation stay unchanged, including any initial negative values. With no
operations, return the sum of the original slots. Inputs keep additions and
intermediate sums within the i64 range.
| Initial slots | Operations | Final slots | Returned total |
|---|---|---|---|
[1, 1] |
[3, 4, 5] |
[9, 5] |
14 |
[10] |
[-3, -4] |
[3] |
3 |
[2, 2, 2] |
[-9] |
[0, 2, 2] |
4 |
nudge adds d to its optional slot, clamps the result to zero and returns
the final value. For None, it does nothing and returns 0. Keep its two
update steps separate to practice borrowing from the same Option twice.
This function does not need to call consume.
The harness first calls tally, saves its total and resulting slots, then
calls nudge on the first slot. Its output contains total, after_tally,
nudged and the final slots after both functions.
Why the starter moves a reference
Shared references (&T) implement Copy; mutable references (&mut T)
do not. Moving a mutable reference transfers that reference, so its old
binding cannot be read afterward. This is what happens in consume(r)
when the generic type T is inferred from r.
A reborrow creates a reference through an existing reference. The
expression &mut *r borrows the value reached through r for a new mutable
access. That access must fit within the original borrow's lifetime; it need
not always be strictly shorter. While the mutable reborrow is still needed,
conflicting use through the original reference is disallowed. After its last
use, the original can be used again.
When Rust inserts a reborrow
A parameter with a known mutable-reference type provides enough context:
fn double(r: &mut i64) { *r *= 2; }
fn main() {
let mut n = 1;
let r = &mut n;
double(r);
double(r);
assert_eq!(n, 4);
}
Each call can reborrow r, as if written double(&mut *r). By contrast,
consume(r) infers T from the argument and moves the reference. Writing
consume(&mut *r) makes the intended temporary access explicit.
Generic functions do not always prevent reborrowing: explicitly supplying a
reference type, as in consume::<&mut i64>(r), also provides type context.
Struct fields can provide that context too:
struct Slot<'a> { value: &'a mut i64 }
fn main() {
let mut n = 1;
let r = &mut n;
let slot = Slot { value: r };
*slot.value += 1;
*r += 1;
assert_eq!(n, 3);
}
Here the field use finishes before r is used again. If a later use of
slot.value still needed the reborrow, that overlapping access through r
would be rejected. Look at the expected type and later uses rather than
treating all function calls or struct initializers alike.
Reusing the optional reference
In the starter, if let Some(r) = slot moves the contained &mut i64 into
r. A second match cannot move it out again. Option<&mut i64> does not
implement Copy, and Rust does not automatically rebuild that wrapper
around a reborrow.
slot.as_deref_mut() borrows the option mutably and returns a new
Option<&mut i64> borrowing the value reached through its contained
reference. Match that temporary option for each update. The original
option remains available once each borrow ends, including for the final
map_or call. The binding must be mutable to call as_deref_mut().
as_mut() is another option, but it returns Option<&mut &mut i64> here,
so updating the integer requires one more dereference.
Complete the repair
Use explicit reborrows for the two consume calls in tally, and borrow
from the option for the two updates in nudge. Keep the generic helper's
signature and body: changing it to a concrete mutable-reference function
would bypass the part of the exercise that demonstrates type inference.
Check both returned values and mutations, then address Clippy warnings. Passing requires compilation, correct results and the lint gate.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.