We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Ownership II: Borrowing and the Borrow Checker step 14 of 24
Carry a running maximum through mutable iteration
Implement two functions that update existing slices in place.
pub fn running_max_in_place(xs: &mut [i64])
pub fn zip_add(dst: &mut [i64], src: &[i64])
running_max_in_place replaces each element with the largest original value
seen up to that position. For example, [3, 2, 1] becomes [3, 3, 3], while
[-5, -9, -1] becomes [-5, -5, -1]. An empty slice stays empty.
zip_add adds matching source values to the destination until either slice ends. Leave any remaining destination elements unchanged and ignore unused source elements. It must not modify src.
| Destination before zip_add | Source | Destination after |
|---|---|---|
[5, 5] |
[1] |
[6, 5] |
[1] |
[2, 3] |
[3] |
[] |
[1, 2] |
[] |
[7] |
[] |
[7] |
Use mutable iteration and a scalar accumulator rather than allocating a replacement vector. Inputs are chosen so the additions fit in i64; wrapping or saturating arithmetic is not required.
The harness applies both functions
First it applies running_max_in_place to xs and saves that intermediate result. Then it applies zip_add to the updated xs using src. The response contains both running_max and final. It does not compute another running maximum after the addition, so final need not be nondecreasing.
xs = [3, 2, 4], src = [0, -5]
running_max = [3, 3, 4]
final = [3, -2, 4]
Carry a value instead of borrowing the previous element
The starter tries to keep two indexed mutable borrows of xs live at once. Although the indices differ, the compiler rejects that form with E0499. For this calculation, the previous maximum can be held as an independent i64.
Initialize best to i64::MIN. For each mutable element reference, update best with the larger of best and the current value, then write best back through that reference. i64::MIN handles negative inputs and the smallest possible value; an empty slice simply skips the loop.
Mutable iterator items can coexist
IterMut yields references to distinct elements. An item's lifetime is tied to the borrowed slice, rather than the short borrow used to call next. You can therefore keep one item while requesting another:
fn main() {
let mut values = [10, 20];
let mut iter = values.iter_mut();
let first = iter.next().unwrap();
let second = iter.next().unwrap();
*first += 1;
*second += 2;
assert_eq!(values, [11, 22]);
}
Safety depends on the iterator never yielding the same element twice and restricting its access to the remaining elements. The lifetime signature alone does not establish that property. Mutable references to different elements can be live together; conflicting access to the same element is the issue.
See the IterMut documentation and the Rustonomicon's borrow-splitting explanation.
Pair destination and source with zip
The starter's zip_add loops over the entire destination and indexes the source. It panics when the source is shorter. Pair dst.iter_mut() with src instead: zip stops producing pairs when either iterator ends, matching the required shorter-slice behavior.
A carefully bounded indexed loop can also be correct. Mutable iteration is the requested form here because it directly expresses the paired updates. No performance comparison is established by the output tests.
Passing requires compilation, tests and Clippy with warnings denied.
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.