1

I'm implementing Conway's Game of Life in various forms to reacquant myself with Rust. Currently I'm writing an implementation to use an iterator instead of nested for loops and got stuck on a lifetime issue.

I believe the lifetime annontations correct for the iterator types. However when I go to bind a cell state to the iterator return type, the borrow checker doesn't believe it's a valid assignment. What am I missing in my implementation to allow the borrow checker to succeed?

This is the current implementation of the iterator:

struct LifeBoard {
    board_size: usize,
    cells: std::vec::Vec<bool>,
}
struct Cell<'a> {
    row : usize,
    col : usize,
    state : &'a mut bool
}

struct CellIterator<'a> {
    board : &'a mut LifeBoard,
    index : usize
}

impl<'a> std::iter::Iterator for CellIterator<'a> {
    type Item = Cell<'a>;

    fn next(&mut self) -> Option<Cell<'a>> {
        if self.index < self.board.cells.len() {
            let board_size = self.board.board_size;
            let row = self.index / board_size;
            let col = self.index % board_size;
            let state : &'a mut bool =  &mut self.board.cells[self.index];
            self.index = self.index + 1;

            Some( Cell { row, col, state } )
        } else {
            None
        }
    }
}

impl LifeBoard {
    fn new(board_size: usize) -> LifeBoard {
        let mut cells = Vec::new();
        cells.resize(board_size * board_size, false);

        LifeBoard { board_size, cells }
    }

    fn iter_cells_mut( &mut self ) -> CellIterator {
        CellIterator{ board: &mut self, index: 0 }
    }
}

This is the error message:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
   --> src\main.rs:116:46
    |
116 |             let state : &'a mut bool =  &mut self.board.cells[self.index];
    |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 109:5...
   --> src\main.rs:109:5
    |
109 | /     fn next(&mut self) -> Option<Cell<'a>> {
110 | |         if self.index < self.board.cells.len() {
111 | |             None
112 | |         } else {
...   |
120 | |         }
121 | |     }
    | |_____^
note: ...so that reference does not outlive borrowed content
   --> src\main.rs:116:46
    |
116 |             let state : &'a mut bool =  &mut self.board.cells[self.index];
    |                                              ^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 106:6...
   --> src\main.rs:106:6
    |
106 | impl<'a> std::iter::Iterator for CellIterator<'a> {
    |      ^^
note: ...so that reference does not outlive borrowed content
   --> src\main.rs:116:41
    |
116 |             let state : &'a mut bool =  &mut self.board.cells[self.index];
BlamKiwi
  • 2,093
  • 2
  • 19
  • 30
  • 1
    My Rust is not what it could be, but I believe the error-message is complaining that (1) the `next` method un-borrows its `self` argument when it returns and (2) it returns a mutable reference to part of that argument. Either #1 or #2 could be fine on its own, but the two of them together are in conflict; you can't keep a reference to something you've un-borrowed. – ruakh Jan 06 '19 at 08:30
  • 1
    I ended up finding a post that explains the problem well. https://stackoverflow.com/questions/25730586/how-can-i-create-my-own-data-structure-with-an-iterator-that-returns-mutable-ref – BlamKiwi Jan 06 '19 at 09:56

0 Answers0