The Rust borrow checker guarantees that if a value is mutably borrowed, it should not be borrowed (mutably or not) a second time until the lifetime of the first borrow ends.
NLL (non-lexical lifetime) is a new Rust feature that makes the lifetime of a borrow end when it’s not used anymore in the lexical scope, rather than live until the borrow effectively exits the lexical scope. I see this feature working when I need to manipulate a borrowed structure (for example, calling mutating methods on values inside it), but it seems to not work when I call a function that seemingly does a second borrow on the structure itself. NLL should be able to automatically end a borrow when it sees that it’s not used anymore in the scope, so that a second (mutable) borrow can happen in that scope without triggering error.
Let’s see how my code looks like:
fn handle_menu_transition(&mut self, transition: MenuTransition) {
match transition {
MenuTransition::Quit => self.quitting = true,
MenuTransition::StartGame => self.state = ClientState::Playing(Game::default()),
_ => {}
}
}
fn update(&mut self) -> bool {
let now = std::time::Instant::now();
let delta_time = now - self.last_update;
self.last_update = now;
match &mut self.state {
ClientState::MainMenu(menu) => {
self.handle_menu_transition(menu.update(delta_time));
true
}
ClientState::Playing(game) => {
self.render()
}
ClientState::PauseMenu(menu, game) => {
self.handle_menu_transition(menu.update(delta_time));
self.render()
}
}
}
For additional informations, self.render
is a non-mutating method, MenuTransition
is an enum that derives Copy/Clone, and menu.update
is a mutating method on my Menu
structure, so the self.state
enum needs to be borrowed mutably (because Menu
is contained inside the state).
I don’t understand why the NLL feature cannot see that after each call to handle_menu_transition
, the first borrow (in the match
clause) is not used anymore, so it’s possible to drop it here so that the second borrow (at call of handle_menu_transition
) can happen. If I remove the handle_menu_transition
method altogether from my code and copy-paste the code inside it at the call site, or if I save the MenuTransition
resulting from menu.update()
in a separate variable before calling handle_menu_transition
, the borrow checker does not complain anymore. Do you know why it is so ?