How to edit data structure from the higher scope in a callback

I'm trying to combine two parts of the toy project together and thanks to the helping of the community I got close to reach the goal. I understood that Box is the proper way of implementing callback if an argument of callback is a complex data structure. And to use variable from the higher scope of a callback move should be used with callback and Box with the variable you want to use. Thank you.

Now I am struggling to find a way to edit data structure from the higher scope in a callback. Minimal code is:


fn main()
{
  let mut mechanics = Box::new( Mechanics { val : 13. } );
  let mut renderer = Render::new( "solution1".to_string() );
  renderer.f_on_update = Box::new( move | e |
  {
    println!( "mechanics.val : {}", mechanics.val );
    mechanics.val = 3.;
    println!( "dt : {}", e.dt );
  });
  renderer.update();
}

//

struct UpdateEvent<'a>
{
  dt : f64,
  renderer : &'a mut Render,
}

//

struct Mechanics
{
  val : f32,
}

//

struct Render
{
  name : String,
  f_on_update : Box< dyn FnMut( &mut UpdateEvent ) >,
}

//

impl Render
{
  fn new( name : String ) -> Self
  {
    let f_on_update = | _e : &mut UpdateEvent | {};
    Self { name, f_on_update : Box::new( f_on_update ) }
  }
  fn update( &mut self )
  {
    let mut e = UpdateEvent { dt : 1.0, renderer : self };
    (self.f_on_update)( &mut e );
  }
}

It gives error:

error[E0499]: cannot borrow `self.f_on_update` as mutable more than once at a time
  --> src/static_with_event_solution_1.rs:50:5
   |
49 |     let mut e = UpdateEvent { dt : 1.0, renderer : self };
   |                                                    ---- first mutable borrow occurs here
50 |     (self.f_on_update)( &mut e );
   |     ^^^^^^^^^^^^^^^^^^  ------ first borrow later used here
   |     |
   |     second mutable borrow occurs here

Here is playground with the code.

Any suggestion to overcome the problem or reading which might be helpful?

You can factor the non-closure fields of Render into their own struct. This way you can borrow the closure (necessary to call it) and the rest of the struct (which you're using as part of the argument) at the same time without overlapping the borrows.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.