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

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

问题描述

我有一个 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.

我尝试了几件事:

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

  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>.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 仅限于实现 Copy 的类型(对于其他类型,您必须使用 RefCell,如果涉及多个线程,则必须使用 ArcMutex).

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天全站免登陆