我试图使用
ndarray库在Rust中实现
Conway’s Game of Life的一次迭代.
我认为在数组上循环的3×3窗口将是计算生活邻居的简单方法,但是我在进行实际更新时遇到了麻烦.
阵列用#表示生命,没有生命:
let mut world = Array2::<String>::from_elem((10, 10), " ".to_string());
for mut window in world.windows((3, 3)) {
let count_all = window.fold(0, |count, cell| if cell == "#" { count + 1 } else { count });
let count_neighbours = count_all - if window[(1, 1)] == "#" { 1 } else { 0 };
match count_neighbours {
0 | 1 => window[(1, 1)] = " ".to_string(), // Under-population
2 => {}, // Live if alive
3 => window[(1, 1)] = "#".to_string(), // Re-produce
_ => window[(1, 1)] = " ".to_string(), // Over-population
}
}
这段代码不能编译!错误在匹配块内,“错误:不能借用可变”和“错误:无法分配给不可变索引”.我尝试了& mut窗口……但是库没有实现这个(?)
我是Rust的新手,我相信这可能是图书馆实施windows的问题.但是,我不确定,我不知道是否有一些变化/修复允许我继续这种方法.我是否需要完全废弃这种方法?我不确定这里最好的方法是什么.
对代码的任何其他建议或改进将不胜感激.
(这段代码没有实现正确的规则,因为我在循环变异,我忽略了外边缘,但是在这种情况下也没关系.另外,做这些事情的任何变化都没关系 – 细节并不重要. )
最佳答案 你使用ndarray和windows的一般方法是可以的,但问题是你从windows迭代器得到的值总是不可变的.您可以通过将值包装在Cell或RefCell中来解决这个问题,从而为您提供内部可变性.也就是说,它们将一个值包装成好像是不可变的,但是提供一个API来让你无论如何都要改变它.
这是你的代码,相当粗暴地适应使用RefCell:
use ndarray::Array2;
use std::cell::RefCell;
fn main() {
// creating variables for convenience, so they can be &-referenced
let alive = String::from("#");
let dead = String::from(" ");
let world = Array2::<String>::from_elem((10, 10), " ".to_string());
let world = world.map(RefCell::new);
for mut window in world.windows((3, 3)) {
let count_all = window.fold(0, |count, cell| if *cell.borrow() == &alive { count + 1 } else { count });
let count_neighbours = count_all - if *window[(1, 1)].borrow() == &alive { 1 } else { 0 };
match count_neighbours {
0 | 1 => *window[(1, 1)].borrow_mut() = &dead, // Under-population
2 => {}, // Live if alive
3 => *window[(1, 1)].borrow_mut() = &alive, // Re-produce
_ => *window[(1, 1)].borrow_mut() = &alive, // Over-population
}
}
}
我上面所做的只是为了让你的代码正常工作,几乎就是这样.但是,正如E_net4指出的那样,你的解决方案有一个主要的错误,因为它在读取时会发生变异.此外,就最佳实践而言,您对String的使用并不理想.枚举更好,因为它更小,可以堆栈分配,更好地捕获模型的不变量.使用枚举,您将获得如下所示的复制,这将允许您使用Cell而不是RefCell,这可能是更好的性能,因为它复制数据,而不必计算引用.
#[derive(Debug, PartialEq, Clone, Copy)]
enum CellState {
Alive,
Dead
}