How can I solve my "cannot borrow as mutable because it is also borrowed as immutable" problem

Here is a minimal example of my problem: I have a stage (here in 1D for simplicity) and a struct that holds some parameters for that stage. The center() parameter here is a very simplified example. My restrictions are:

  • StageStats evaluates parameters for a given & Stage1D content (immutable reference)
  • the calculated values must be stored (cached) within a StageStats instance that evaluated them

Because I always need both Stage1D and StageStats in any given time, I contained one inside the other, and here is where the problem starts:

cannot borrow `self.my_stats` as mutable because it is also borrowed as immutable

I understand why my code can be dangerous and why Rust doesn't allow me to write that. My question is: what are my other options to implement that (besides moving StageStats out of Stage1D)

pub struct Stage1D {
    points: Vec<f32>,
    my_stats: StageStats,
}

pub struct StageStats { recent_center:f32 }

impl StageStats {
    pub fn center(&mut self, s:&Stage1D) -> f32 { 
        let sum : f32 = s.points.iter().sum();
        self.recent_center = sum / s.points.len() as f32;
        return self.recent_center;
    }
}

impl Stage1D {
    pub fn new() -> Stage1D { Stage1D{points: Vec::new(), my_stats: StageStats{recent_center:0.0}} }
    pub fn my_center(&mut self) -> f32 { self.my_stats.center(&self) }
}

fn main ()
{
    let _ = Stage1D::new();
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `self.my_stats` as mutable because it is also borrowed as immutable
  --> src/main.rs:18:42
   |
18 |     pub fn my_center(&mut self) -> f32 { self.my_stats.center(&self) }
   |                                          ^^^^^^^^^^^^^^------^-----^
   |                                          |             |      |
   |                                          |             |      immutable borrow occurs here
   |                                          |             immutable borrow later used by call
   |                                          mutable borrow occurs here

For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` due to previous error

I would have split Stage1D into two structs : data and stats.
So you can immutably borrow data part and pass it to stats.

pub struct Stage1D {
    data: StageData,
    my_stats: StageStats,
}

pub struct StageData {
    points: Vec<f32>,
}

pub struct StageStats { recent_center:f32 }

impl StageStats {
    pub fn center(&mut self, s:&StageData) -> f32 { 
        let sum : f32 = s.points.iter().sum();
        self.recent_center = sum / s.points.len() as f32;
        return self.recent_center;
    }
}

impl Stage1D {
    pub fn new() -> Stage1D { Stage1D{ data: StageData {points: Vec::new()}, my_stats: StageStats{recent_center:0.0}} }
    pub fn my_center(&mut self) -> f32 { self.my_stats.center(&self.data) }
}

Maybe center() can be a method of stage1D?

View structs are one way.

Here's an article on the topic with some other approaches.

Oh no, the poor error formatting has really gone off the rails here...