Reputation: 413
I currently want to define a struct for a Piston game using GamerIterator:
pub struct MyGame<'a> {
game_window: GameWindowGLFW,
game_iter: GameIterator<'a, GameWindowGLFW>,
//...
}
The GameIterator
is generic in the GameWindow
and its lifetime. I want to tell the compiler that it has the same lifetime as the field "game_window"/"the whole struct" and leave out the lifetime for the struct.
I also have difficulties initializing this:
MyGame {
game_window: GameWindowGLFW::new(GameWindowSettings {/*...*/},
game_iter: GameIterator::new(&mut game_window, &game_iter_settings), // game_window cannot be used here
//...
}
I think that I can work around the initialization issue by using Option<GameIterator<...>>
and an init() method, but I would like to avoid this because I can guarantee that game_iter
is present after new()
finishes.
What is the idiomatic way to write this?
Upvotes: 41
Views: 11418
Reputation: 65682
Not only is there an issue with initialization, there could also be issues with destruction, if GameIterator
implemented Drop
: the compiler would have to know that it needs to destruct game_iter
before game_window
, otherwise game_window
would have a reference to a destroyed GameWindowGLFW
while running its drop()
method.
There's no way to pass the lifetime of the struct itself as a lifetime argument. The only thing you can do is remove the game_window
field from MyGame
and pass a GameWindowGLFW
instance to MyGame
's initializer. If you want to encapsulate this so that the user doesn't need to create a GameWindowGLFW
, you could write a method that creates a GameWindowGLFW
and a MyGame
on the stack and calls a closure that accepts a MyGame
argument only.
pub struct MyGame<'a> {
game_iter: GameIterator<'a, GameWindowGLFW>,
//...
}
impl<'a> MyGame<'a> {
fn new(game_window: &'a mut GameWindowGLFW) -> MyGame<'a> {
MyGame {
game_iter: GameIterator { game_window: game_window },
}
}
}
fn start_game(callback: |game: &mut MyGame|) {
let mut game_window = GameWindowGLFW;
let mut game = MyGame::new(&mut game_window);
callback(&mut game);
}
fn main() {
start_game(|game| {
/* use game here */
});
}
Upvotes: 19