I have some implementations of GameManager, such as SnakeGameManager and TetrisGameManager, ...
I want to store mutable reference to GameManager instantiations
I have a struct that holds a Vec<Rc<Mutex<dyn GameManager in my main struct as i think is a good way to do that
I want to create a vector to store different instances of these implementations, so i can go from one to the another while still having them both to go back and forth, the think is, the borrow checker is complaining when i try to create a instance of them, here is part of my code:
struct TGamesManager {
terminal: Terminal<CrosstermBackend<Stdout>>,
game_instance: Vec<Option<Rc<Mutex<dyn game_manager::GameManager>>>>,
// Stuff
}
impl TGamesManager {
fn create_run_game(&mut self, game: Games) -> Result<()> {
if let Ok(true) = match game {
Games::Snake => {
if self.game_instance[self.game_index].is_none() {
self.game_instance.insert(
self.game_index,
Some(Rc::new(Mutex::new(SnakeGameManager::new(&mut self.terminal)))),
);
}
if let Some(game_instance) = &mut self.game_instance[self.game_index] {
game_instance.lock().unwrap().run()
} else {
Ok(false)
}
}
_ => Ok((false))
} {
self.kill_execution = true;
}
Ok(())
}
}
The borrow checker says that "Some(Rc::new(Mutex::new(SnakeGameManager::new())))," will not live long enough, how can i fix that ? Disclaimer: i'm new to the rust world and don't know a lot about the rust types
We need more context to understand the problem. Please run cargo check and copy its entire output — not just a single line. Everything the compiler prints is meant to help you, and it'll help us understand what your situation is.
(Also, your code could be simpler if you used Option::get_or_insert_with(). But maybe don't change things till we've figured out what the current situation is.)
Yes, that is a very important detail. You cannot do that — not and store the SnakeGameManager in TGamesManager; it creates a “self-referential struct” which is not natively supported by Rust (and would not work at all for this purpose, if you want to be able to ever drop the borrow and reuse self.terminal).
For this purpose, you should pass &mut self.terminal to run() instead of storing it inside the SnakeGameManager. As a general principle, you almost never want to put a lifetime parameter on your structs — even though Rust supports it, it's very rarely the right choice.
Thanks for the heads up, i can see why that's the case now. I'm gonna follow your advice removing the lifetimes and passing the self.terminal to run() instead and i'm gonna give a look into Option::get_or_insert_with() as you recommended. Thank you once again!
&mut _ are exclusive references, so you can't have two independent &mut to the same Terminal at the same time (e.g. by storing them in multiple Vec slots)
Another thing to consider is that all loans (references to fields and variables) are temporary, limited to their scope, and nothing can change that. Putting a short lived loan in a long-lived Arc will make Arc short-lived and temporary, and not the other way around.
Arc is only useful if it owns it content, and there are no references inside it anywhere.