Skip to content

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

Medium Primitives

Subtract the minimum with a mutable iterator

Rewrite the starter's indexed loop to update the slice through a mutable iterator.

pub fn subtract_min(xs: &mut [i64]) -> i64

Find the smallest element, subtract it from every element in place, and return that original minimum. Preserve element order and slice length. An empty slice stays empty and returns 0. Inputs are restricted to values whose differences from the minimum fit in i64; wrapping and saturating subtraction are not required.

Input Returned minimum Slice after the call
[] 0 []
[5] 5 [0]
[3, 3, 3] 3 [0, 0, 0]
[-2, 4, 0] -2 [0, 6, 2]
[0, 7] 0 [0, 7]

The starter computes these results correctly, but Clippy reports needless_range_loop: the loop uses its index only to access each element. Passing requires compilation, correct results and Clippy with warnings denied.

Copy the minimum before mutating

xs.iter().min() returns Option<&i64>. Keeping that reference and using it while changing the slice creates conflicting borrows. For example, this function does not compile:

fn conflicting_borrows(xs: &mut [i64]) {
    let minimum = xs.iter().min();
    for value in xs.iter_mut() {
        *value -= minimum.unwrap();
    }
}

Copy the integer out of the reference first. The starter already does this with Some(v) => *v, so its minimum does not borrow the slice. Another form is:

let Some(&minimum) = xs.iter().min() else {
    return 0;
};

This fragment belongs inside subtract_min. The pattern copies an i64 into minimum and handles the empty case. No reference into xs is retained for the update loop.

Visit the elements directly

xs.iter_mut() yields one mutable reference per element, in slice order. Use each reference to subtract the copied minimum. This avoids writing a separate index range and indexed access when neither is needed.

The borrow fix and the loop rewrite solve different problems: copying the minimum removes the conflicting shared borrow; mutable iteration expresses which elements to update. Switching loops alone would not fix a retained reference to the minimum.

Indexing is still useful when positions are part of an algorithm, such as binary search or a table lookup. Indexed access has bounds-checking semantics, but an optimizer can remove redundant checks. This exercise does not establish a speed advantage for either form; choose the iterator here for the direct expression of visiting every element.

See Clippy's needless_range_loop documentation.