How do I keep a reference to a selected element?

Here is the full code in question.

I'm making an app using the Nannou framework. I would like to keep a reference to the selected cell in my model, but I'm fighting the borrow checker on this one. It complains that I am borrowing the grid value after move, and that I cannot return a value referencing data owned by the current function. How can I make this work?

#[derive(Default)]
struct Grid {
    state: [[Cell; 9]; 9],
}

struct Model<'a> {
    grid: Grid,
    selected: &'a mut Cell,
}

impl<'a> Model<'a> {
    fn select(&'a mut self, x: usize, y: usize) {
        self.selected = &mut self.grid.state[x][y];
    }
}

fn model(app: &App) -> Model<'static> {
    let _window = app.new_window()
        .view(view)
        .key_pressed(key_pressed)
        .build()
        .unwrap();
    let mut grid = Grid::default();
    Model {
        grid,
        selected: &mut grid.state[0][0],
    }
}

It is right: this would cause immediate undefined behaviour. If you are lucky, it will crash. If you're not lucky, your program will just behave incredibly weirdly.

You don't. You can't return references to locals, and you can't generally construct self-referential types (i.e. types that contain a pointer to themselves).

Instead, I would change selected to be the indices for the currently selected cell, with a type of (u8, u8) (which would be large enough given the size limit of 9 for each dimension).

...

Well, okay, you can make self-referential types using certain crates, but I'm not going to recommend any for two reasons: 1. every time someone releases one, it's later proven to be unsound, and 2. I forget which is the current "totally safe this time guys I promise" crate for this.

It's simply easier and safer to use an index instead of a reference.

5 Likes

You can't use references for this purpose. I recommend storing the indexes instead.

1 Like