I have a Board
(a.k.a. &mut Vec
) which I would like to update while iterating over it. The new value I want to update wi
It entirely depends on your next_gen
function. Assuming we know nothing about the function except its signature, the easiest way is to use indices:
fn step(board: &mut Board) {
for row_index in 0..board.len() {
for column_index in 0..board[row_index].len() {
let cell_next = next_gen((row_index, column_index), &board);
if board[row_index][column_index] != cell_next {
board[row_index][column_index] = cell_next;
}
}
}
}
With more information about next_gen
a different solution might be possible, but it sounds a lot like a cellular automaton to me, and to the best of my knowledge this cannot be done in an iterator-way in Rust without changing the type of Board
.
You might fear that the indexing solution will be less efficient than an iterator solution, but you should trust LLVM on this. In case your next_gen
function is in another crate, you should mark it #[inline]
so LLVM can optimize it too (not necessary if everything is in one crate).
Not an answer to your question, but to your problem:
Since you are implementing Conway's Game of Life, you cannot do the modification in-place. Imagine the following pattern:
00000
00100
00100
00100
00000
If you update line 2, it will change the 1
in that line to a 0
since it has only two 1
s in its neighborhood. This will cause the middle 1
to see only two 1
s instead of the three that were there to begin with. Therefor you always need to either make a copy of the entire Board
, or, as you did in your code, write all the changes to some other location, and splice them in after going through the entire board.
Is there a way that I could make this code update the board "in place"?
There exists a type specially made for situations such as these. It's coincidentally called std::cell::Cell. You're allowed to mutate the contents of a Cell
even when it has been immutably borrowed multiple times. Cell
is limited to types that implement Copy
(for others you have to use RefCell, and if multiple threads are involved then you must use an Arc in combination with somethinng like a Mutex).
use std::cell::Cell;
fn main() {
let board = vec![Cell::new(0), Cell::new(1), Cell::new(2)];
for a in board.iter() {
for b in board.iter() {
a.set(a.get() + b.get());
}
}
println!("{:?}", board);
}