How to change a field in a closure?

I'm learning rust. I'm completely stuck. I have a vector of closures. and I try to change the count field.
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=200dfe81321d50fb87c7f19fa082cde7

use std::cell::RefCell;
use std::rc::Rc;

#[derive(Clone)]
pub struct Callbacks {
    callbacks: Vec<Rc<RefCell<dyn FnMut()>>>,
}

impl Callbacks {
    pub fn new() -> Self {
        Callbacks {
            callbacks: Vec::new(),
        }
    }

    pub fn register<F: FnMut() + 'static>(&mut self, callback: F) {
        let cell = Rc::new(RefCell::new(callback));
        self.callbacks.push(cell); /*@*/
    }

    pub fn call(&mut self) {
        for callback in self.callbacks.iter() {
            let mut closure = callback.borrow_mut();

            (&mut *closure)();
        }
    }
}

struct App {
    count: f32,
    cb: Callbacks,
}
impl App {
    fn new() -> Self {
        App {
            count: 0.0,
            cb: Callbacks::new(),
        }
    }
    fn some_fn(&mut self) {
        let count = RefCell::new(self.count);
        self.cb.register(|| {
            *count.borrow_mut() += 1.0;
        });
    }
}

fn main() {
    let mut app = App::new();
    app.some_fn();
    app.cb.call();
    println!("{}", app.count);
}


   Compiling playground v0.0.1 (/playground)
error[E0373]: closure may outlive the current function, but it borrows `count`, which is owned by the current function
  --> src/main.rs:43:26
   |
43 |         self.cb.register(|| {
   |                          ^^ may outlive borrowed value `count`
44 |             *count.borrow_mut() += 1.0;
   |              ----- `count` is borrowed here
   |
note: function requires argument type to outlive `'static`
  --> src/main.rs:43:9
   |
43 | /         self.cb.register(|| {
44 | |             *count.borrow_mut() += 1.0;
45 | |         });
   | |__________^
help: to force the closure to take ownership of `count` (and any other referenced variables), use the `move` keyword
   |
43 |         self.cb.register(move || {
   |                          ^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0373`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

how can i solve this problem.? I also tried to use the keyword "move". but the count value remains 0.0.

The register asks for FnMut() + 'static closures, and that 'static means that it doesn't want any closures which reference temporary variables.

count is a temporary variable, so a closure that references it isn't 'static any more (its lifetime is narrowed to scope of the some_fn function call, which is smaller than scope of self.cb).

count will be destroyed at the end of some_fn, so if this code compiled, calling of the closure would overwrite some other memory on the stack, causing nasty memory corruption.

You have to move the count to be owned by the closure, like the compiler suggests. move || makes variables used by the closure owned by the closure itself, so they will live for as long as the closure lives.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.