[solved] Help with passing in a value to a function that is used in a closure

#1

I’m just getting started with Rust and am running into an issue that’s leaving me scratching my head.

I am programming the Game of Life and using the Cursive crate to render a visualization in the terminal.
The issue I’m running into is that I’m trying to pass in an instance of the game grid to the display_curses_grid function that renders the grid and also adds a Cursive global callback (closure) that advances the grid and redraws it when a key is pressed. My code compiles and runs fine when the grid is instantiated (as mut) in the display_curses_grid function, but I run into a serious wrestling match with the compiler when I try to refactor my code so that the display function accepts the grid to display.

Here are the relevant functions:

type Grid = Vec<Vec<bool>>;

fn main() {
  let mut siv = Cursive::default();
  siv.add_global_callback('q', |s| s.quit());
  display_curses_grid(&mut siv);
  siv.run();
}

fn display_curses_grid(siv: &mut cursive::Cursive) {
  let mut grid = make_default_grid();
  siv.add_layer(
    Dialog::new()
      .title("Game of Life")
      .padding((2, 2, 1, 1))
      .content(LinearLayout::vertical().child(BoardView::new(grid.to_vec()))),
  );
  siv.add_global_callback('n', move |s| {
    grid = tick(grid.to_vec());
    s.pop_layer();
    s.add_layer(
      Dialog::new()
        .title("Game of Life")
        .padding((2, 2, 1, 1))
        .content(LinearLayout::vertical().child(BoardView::new(grid.to_vec()))),
    );
  });
}

pub fn tick(grid: Grid) -> Grid {
  let len = grid[0].len();
  let mut new_grid = vec![vec![false; len]; len];

  for y in 0..len {
    for x in 0..len {
      let data = neighbor_data(x as i32, y as i32, &grid);
      new_grid[y][x] = match data {
        (alive, _, true) if alive < 2 => false,
        (alive, _, true) => alive == 2 || alive == 3,
        (alive, _, false) => alive == 3,
      };
    }
  }
  new_grid
}

When I change the code so that main instantiates the grid and change the display_curses_grid function to accept a second grid parameter, I run into some difficulty and so far haven’t been able to figure out what to change to get the compiler happy.

Initially I tried instantiating the grid in main and adding the grid: &mut Grid as the 2nd param to display_curses_grid, but that results in a mismatched types error "expected mutable reference, found struct std::vec::Vec", as described in this commit: https://github.com/bantic/game_of_life_rust/commit/c5306d7612ff1979d5d61d1b8f7be6d00a11ac92

If I accept the compiler’s suggestion of mutably borrowing the grid.to_vec() I get the new error “lifetime static required”. Here’s the commit along with its new compiler error:

Can anyone help explain to me how I could do the refactoring I’m looking to do, and/or explain what these errors are describing?

Thank you!

#2

If your only after instantiation in main then you can just move the type into the function.
fn display_curses_grid(siv: &mut cursive::Cursive, mut grid: Grid)

If you want to maintain some separate ownership then basic references won’t work (The closure taken by add_global_callback must be 'static i.e. is unbound by references.) Instead Rc<RefCell<_>> is often used.

#3

Thanks for the suggestion. That worked! I think I need to study up some more to understand the RefCell.