Hiya, I'm using the cursive
crate to try to make the UI for a game. I have a GameState
struct which I want to mutate using callbacks attached to cursive
's buttons. My understanding is that because the callback only takes the UI as an input, the callback must capture the gamestate, but the compiler doesn't allow this because it causes an ownership issue?
The error mentioned closures specifically, so I tried factoring out the closure into a proper function but that didn't help either. When I move the callback to be a named variable, the compiler says expected a closure that implements the
Fn trait, but this closure only implements FnMut
, so it looks to me that I can't mutate the gamestate from that callback.
If I'm going about this the wrong way then please let me know, thank you.
Here's a MWE to show the problem I'm having:
use cursive::views::Button;
use cursive::views::Dialog;
use cursive::views::TextView;
use cursive::Cursive;
pub struct GameState {
pub day: usize,
}
fn main() {
// Set up the game
let mut g = GameState { day: 1 };
let mut ui = cursive::default();
// Create the UI
let button_next_day = Button::new("Next day", move |s: &mut Cursive| {
// Mutate game state
g.day += 1;
// Mutate the UI to show a dialog
let popup_text = format!("It is now day {}.", g.day);
let popup_layer = Dialog::around(TextView::new(popup_text)).dismiss_button("Ok");
s.add_layer(popup_layer);
});
let main_layer = Dialog::around(button_next_day);
ui.add_layer(main_layer);
ui.run();
}
This produces the following errors:
Errors produced
Compiling test-package v0.1.0 (/home/hannes/Documents/rust/test)
error[E0594]: cannot assign to `g.day`, as `Fn` closures cannot mutate their captured variables
--> src/main.rs:18:9
|
18 | g.day += 1;
| ^^^^^^^^^^ cannot assign
error[E0373]: closure may outlive the current function, but it borrows `g`, which is owned by the current function
--> src/main.rs:16:52
|
16 | let button_next_day = Button::new("Next day", |s: &mut Cursive| {
| ^^^^^^^^^^^^^^^^^ may outlive borrowed value `g`
17 | // Mutate game state
18 | g.day += 1;
| - `g` is borrowed here
|
note: function requires argument type to outlive `'static`
--> src/main.rs:16:27
|
16 | let button_next_day = Button::new("Next day", |s: &mut Cursive| {
| ___________________________^
17 | | // Mutate game state
18 | | g.day += 1;
19 | | // Mutate the UI to show a dialog
... |
22 | | s.add_layer(popup_layer);
23 | | });
| |______^
help: to force the closure to take ownership of `g` (and any other referenced variables), use the `move` keyword
|
16 | let button_next_day = Button::new("Next day", move |s: &mut Cursive| {
| ^^^^^^^^^^^^^^^^^^^^^^