Iterator + Borrow Checker: Work around borrowing already borrowed mutable variable

I am working on a program to map data to a canvas. I have a sample vector of structures that contains the data which will be used to calculate the pixel locations on the canvas and placed via a vector of points. With help from this forum I have worked out calculating the x axis pixels from the data with an iterator but am unable to do so for the y axis. I need to calculate the min and max data values then use the min value in a subsequent calculation to determine the pixel values. Unfortunately I have run into the borrow checker which will not let me immutably borrow the variable min_close in the map method because it is mutably borrowed in the inspect method. I do not understand how to work around this issue. Any assistance will be appreciated.

struct ClosingsByDay {
    date: String,
    closing: f32,
}


pub fn line_graph_x_data() -> Vec<f32> {

    let date_closing_vec: Vec<ClosingsByDay> = vec![
        ClosingsByDay { date:  "2026-02-02".to_string(), closing: 310.05},
        ClosingsByDay { date:  "2026-03-14".to_string(), closing: 322.77},
        ClosingsByDay { date:  "2026-03-29".to_string(), closing: 302.29},
        ClosingsByDay { date:  "2026-04-09".to_string(), closing: 336.45},
        ClosingsByDay { date:  "2026-05-22".to_string(), closing: 352.95},
        ClosingsByDay { date:  "2026-07-15".to_string(), closing: 345.59},
    ];

    let starting_date = NaiveDate::parse_from_str(&date_closing_vec[0].date, "%Y-%m-%d").expect("error");

    let mut duration_iter = date_closing_vec
        .iter()
        .filter_map(|item| NaiveDate::parse_from_str(&item.date, "%Y-%m-%d").ok())
        .map(|nav_date| nav_date.signed_duration_since(starting_date).num_days());

    let last_duration = duration_iter.next_back().unwrap();

    let x_axis = duration_iter
        .map(|duration| duration as f32 / last_duration as f32)
        .chain([1.0])
        .map(|ratio| ((ratio * 600.0) + 100.0).round())
        .collect::<Vec<f32>>();

    for item in &x_axis {
        println!("duration = {}", item);
    }

    let mut max_close = date_closing_vec[0].closing;
    let mut min_close = date_closing_vec[0].closing;
    let close_delta = max_close - min_close;

    let y_axis = date_closing_vec
        .iter()
        .inspect(|element| {
            if element.closing > max_close {
                max_close = element.closing;
            }
            if element.closing < min_close {
                min_close = element.closing;
            }
        })
        
        .map(|element| {

             (700.0 - ((element.closing - min_close) / close_delta) + 100.0).round()    
// cannnot borrow min_close as immutable in above line
// already borrowed as mutable                    

        })
        .collect::<Vec<f32>>();        

    for item in &y_axis {
        println!("y value = {}", item);
    }

    x_axis

}

Could you please post the full error from running cargo check (or the full error from your ide/editor if you can get it)? Often there is a lot more useful info in the error, including references to where min_close is already borrowed.

But from what you posted, I would try moving the code out of the inspect closure and combining it with the code in the map closure.

Combine those .inspect() and .map() into one:

    let y_axis = date_closing_vec
        .iter()
        .map(|element| {
            if element.closing > max_close {
                max_close = element.closing;
            }
            if element.closing < min_close {
                min_close = element.closing;
            }
             (700.0 - ((element.closing - min_close) / close_delta) + 100.0).round()    
        })
        .collect::<Vec<f32>>();

Otherwise both closures must exist at once (their calls are interleaved, at that, so it's not just unfortunate interface), so their captures must not conflict.

UPD: this won't produce the wanted behavior, probably. Am I right that you want to use the minimum of whole vector rather than of the prefix? If so, you do two iterations; the first is much clearer with for rather than inspect.

Below is a more complete error message. I should have posted this initially. My error. Yes, I need both the min and max of the whole vector. I will look into changing the inspect to a for loop as suggested.

error[E0502]: cannot borrow `min_close` as immutable because it is also borrowed as mutable
  --> src/views/line_graph.rs:85:14
   |
76 |         .inspect(|element| {
   |                  --------- mutable borrow occurs here
...
81 |                 min_close = element.closing;
   |                 --------- first borrow occurs due to use of `min_close` in closure
...
85 |         .map(|element| {
   |          --- ^^^^^^^^^ immutable borrow occurs here
   |          |
   |          mutable borrow later used by call
86 |
87 |              (700.0 - ((element.closing - min_close) / close_delta) + 100.0).round()    
   |                                           --------- second borrow occurs due to use of `min_close` in closure


Your logic is somewhat off. Fixing that first may incidentally avoid (or change) the errors you're getting.

    let mut max_close = date_closing_vec[0].closing;
    let mut min_close = date_closing_vec[0].closing;
    let close_delta = max_close - min_close;

close_delta is always 0.0. But later you divide by close_delta.

This is the pertinent question and likely solution IMO:

(The delta of the prefix will still be 0.0 for the first element.)

    let mut max_close = date_closing_vec[0].closing;
    let mut min_close = date_closing_vec[0].closing;
    for closing in date_closing_vec.iter().map(|c| c.closing) {
        max_close = max_close.max(closing);
        min_close = min_close.min(closing);
    }
    let close_delta = max_close - min_close;

I followed the suggestion above and iterated thru the vector twice. This fixed the borrow checker issue. quinedot, you are right regarding close_delta. In addition my final calculation was wrong, I. left out the height of the actual chart (600). All has been fixed and the y_axis values are correct. Thank you one and all once again for the assistance. Below is the updated code.

    let mut max_close = date_closing_vec[0].closing;
    let mut min_close = date_closing_vec[0].closing;

    date_closing_vec
        .iter() 
        .for_each(|element|{
            if element.closing > max_close {
                max_close = element.closing
            }
            if element.closing < min_close {
                min_close = element.closing
            }
        });

    let delta = max_close - min_close;
    
    let y_axis = date_closing_vec
        .iter()
        .map(|element| {
            (700.0 - (600.0 * ((element.closing - min_close) / delta))).round()
        })
        .collect::<Vec<f32>>();    

Unrelated to the borrowing, nonetheless relevant: itertools has minmax, but that means you will iterate twice.

let (min_close, max_close) =
    date_closing_vec
    .iter()
    .map(|e| e.closing)
    .minmax()
    .into_option()
    .unwrap();