如何在迭代集合的同时修改集合? [英] How can I modify a collection while also iterating over it?
问题描述
我有一个 Board
(又名 &mut Vec
),我想在迭代它时更新它.我想要更新的新值来自一个需要 &Vec
到我正在更新的集合的函数.
I have a Board
(a.k.a. &mut Vec<Vec<Cell>>
) which I would like to update while iterating over it. The new value I want to update with is derived from a function which requires a &Vec<Vec<Cell>>
to the collection I'm updating.
我尝试了几件事:
使用
board.iter_mut().enumerate()
和row.iter_mut().enumerate()
以便我可以更新单元格
在最里面的循环中.Rust 不允许调用next_gen
函数,因为它需要一个&Vec
并且当你已经有一个可变引用时你不能有一个不可变引用.>
Use
board.iter_mut().enumerate()
androw.iter_mut().enumerate()
so that I could update thecell
in the innermost loop. Rust does not allow calling thenext_gen
function because it requires a&Vec<Vec<Cell>>
and you cannot have a immutable reference when you already have a mutable reference.
更改 next_gen
函数签名以接受 &mut Vec
.Rust 不允许对一个对象有多个可变引用.
Change the next_gen
function signature to accept a &mut Vec<Vec<Cell>>
. Rust does not allow multiple mutable references to an object.
我目前将所有更新推迟到 HashMap
,然后在执行迭代后应用它们:
I'm currently deferring all the updates to a HashMap
and then applying them after I've performed my iteration:
fn step(board: &mut Board) {
let mut cells_to_update: HashMap<(usize, usize), Cell> = HashMap::new();
for (row_index, row) in board.iter().enumerate() {
for (column_index, cell) in row.iter().enumerate() {
let cell_next = next_gen((row_index, column_index), &board);
if *cell != cell_next {
cells_to_update.insert((row_index, column_index), cell_next);
}
}
}
println!("To Update: {:?}", cells_to_update);
for ((row_index, column_index), cell) in cells_to_update {
board[row_index][column_index] = cell;
}
}
有没有办法让这段代码就地"更新board
,即在最内层循环内,同时仍然能够在其中调用next_gen
最里面的循环?
Is there a way that I could make this code update the board
"in place", that is, inside the innermost loop while still being able to call next_gen
inside the innermost loop?
免责声明:
我正在学习 Rust,我知道这不是最好的方法.我正在四处玩耍,看看我能做什么,不能做什么.我也试图限制任何复制以限制自己一点点.正如 oli_obk - ker 所提到的,Conway 的生命游戏的这种实现存在缺陷.
I'm learning Rust and I know this is not the best way to do this. I'm playing around to see what I can and cannot do. I'm also trying to limit any copying to restrict myself a little bit. As oli_obk - ker mentions, this implementation for Conway's Game of Life is flawed.
此代码旨在衡量几件事:
This code was intended to gauge a couple of things:
- 如果这是可能的
- 如果是惯用的 Rust
根据我在评论中收集到的信息,std::cell::Cell
是可能的.然而,使用 std:cell:Cell
绕过了一些核心 Rust 原则,我在原始问题中将其描述为我的困境".
From what I have gathered in the comments, it is possible with std::cell::Cell
. However, using std:cell:Cell
circumvents some of the core Rust principles, which I described as my "dilemma" in the original question.
推荐答案
有没有办法让这个代码就地"更新电路板?
Is there a way that I could make this code update the board "in place"?
存在一种专为此类情况而设计的类型.它巧合地称为 std::cell::Cell
.你可以改变 Cell
的内容,即使它已经被多次不可变地借用了.Cell
仅限于实现 Copy
的类型(对于其他类型,您必须使用 RefCell
,如果涉及多个线程,则必须使用 Arc
与 Mutex
).
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);
}
这篇关于如何在迭代集合的同时修改集合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!