Prevent Closure from borrowing variable

I am trying to implement a JavaScript function in Rust. The JavaScript function uses closures to change the value of a variable in the closure's surrounding scope. In Rust, I think I understand the closure is borrowing the variable in its surrounding scope (_val) and it is not being updated but moved into the closure. I think I understand that Rust does this because it cannot guarantee that _val will live longer than the closure. I'm looking for a way to use a closure to update _val in the closure's surrounding scope.

fn main() {
let (state, mut set_state) = use_state(0);
assert_eq!(state(), 0);
set_state(2);
assert_eq!(state(), 2);// I would like for state() to be 2 here
}

 fn use_state(initial_value: i32) -> (Box<dyn Fn() -> i32>, Box<dyn FnMut(i32) -> ()>) {
  let mut _val = initial_value; 
  
  let set_state = Box::new(move |new_val| {
        _val = new_val
    });
    
     let state = Box::new(move || {
        _val
    });
 
  (state, set_state) // exposing functions for external use
}

In Rust, values in the function scope are dropped after the function is returned, because in contrast to JS, Rust has no garbage collector that would be able to clean the values up at a later point in time. I believe a more idiomatic way to keep and mutate state would be a mutable struct. I've "ported" your example:

1 Like

Even if you were able to ignore the fact that the stack memory _val is placed in will be destroyed at the end of the function, you're still going to run into problems with the borrow checker.

Your first closure will contain a mutable reference to the value because it wants to set it, while the second closure will need an immutable reference because it wants to read it. However, the borrow checker only allows either 1 mutable reference or many immutable references (for many well-explained reasons that I'm not going to go into here).

It seems like you are trying to use a JavaScript idiom (close over a variable and provide closures to mediate access) in a language which puts an emphasis on being safe in the face of concurrency (i.e. the borrow checker) and not having a runtime which will implicitly transform how things are placed in memory (i.e. in JavaScript, your i32 would be moved from a local variable in the function to the heap, and a pointer passed to both closures).

You may want to explore @mmmmib's solution which uses a struct with getters/setters to mediate access instead... Or even better, cut out the middle man and just pass around a reference to an i32 directly. You can choose to pass around either &i32 or &mut i32 to statically enforce which code is able to mutate your variable and which is only allowed to read it.

1 Like

Thanks for the alternative solutions @Michael-F-Bryan and @mmmmib. I will strongly consider them. What do you think about an approach suggested here using RC and RefCell. Pros and Cons?

Since you originally posted a toy example, i think that's difficult to say without knowing your actual use case. As a general rule of thumb, i'd stick with handing out (mutable) references where that works. Types like Rc<RefCell<T>> (or its multithreading-supporting equivalent Arc<Mutex<T>>) usually come in when things would otherwise get too complex for the borrow checker.

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.