如何修改集合同时迭代它? [英] How can I modify a collection while also iterating over it?

查看:159
本文介绍了如何修改集合同时迭代它?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Board (又名& mut Vec< Vec< Cell>> )喜欢迭代它时更新。我想要更新的新值来自一个函数,该函数需要& Vec< Vec< Cell>> 到我正在更新的集合。

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.

我尝试了几件事:


  1. 使用 board.iter_mut()。enumerate() row.iter_mut()。enumerate()以便我可以更新最内层循环中的。 Rust不允许调用 next_gen 函数,因为它需要& Vec< Vec< Cell>> 并且你当你已经有一个可变引用时,不能有一个不可变引用。

  1. Use board.iter_mut().enumerate() and row.iter_mut().enumerate() so that I could update the cell in the innermost loop. Rust does not allow calling the next_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< Vec< Cell>> 。 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:


  1. 如果这是可能的话

  2. 如果它是惯用的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 仅限于实现复制的类型(对于您必须使用的其他人 RefCell ,如果涉及多个线程然后你必须使用 Arc 互斥 )。

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆