Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize struct fields which reference each other

Tags:

rust

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?

like image 396
maun Avatar asked Aug 12 '14 16:08

maun


People also ask

Can you initialize struct values?

You can also create and initialize a struct with a struct literal. An element list that contains keys does not need to have an element for each struct field. Omitted fields get the zero value for that field.

How do you initialize a struct object?

When initializing an object of struct or union type, the initializer must be a non-empty, (until C23) brace-enclosed, comma-separated list of initializers for the members: = { expression , ... }

How do you initialize a struct member in C++?

// In C++ We can Initialize the Variables with Declaration in Structure. Structure members can be initialized using curly braces '{}'. For example, following is a valid initialization.

How do we initialise a structure give an example?

Initializing structure membersstruct car { char name[100]; float price; }; //car1 name as "xyz" //price as 987432.50 struct car car1 ={"xyz", 987432.50};


1 Answers

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 */
    });
}
like image 64
Francis Gagné Avatar answered Oct 24 '22 03:10

Francis Gagné