本文介绍了从同一个 HashMap 中借用两个可变值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

use std::collections::{HashMap, HashSet};

fn populate_connections(
    start: i32,
    num: i32,
    conns: &mut HashMap<i32, HashSet<i32>>,
    ancs: &mut HashSet<i32>,
) {
    let mut orig_conns = conns.get_mut(&start).unwrap();
    let pipes = conns.get(&num).unwrap();

    for pipe in pipes.iter() {
        if !ancs.contains(pipe) && !orig_conns.contains(pipe) {
            ancs.insert(*pipe);
            orig_conns.insert(*pipe);
            populate_connections(start, num, conns, ancs);
        }
    }
}

fn main() {}

逻辑不是很重要,我正在尝试创建一个函数,它会自行遍历管道.

The logic is not very important, I'm trying to create a function which will itself and walk over pipes.

我的问题是这不能编译:

My issue is that this doesn't compile:

error[E0502]: cannot borrow `*conns` as immutable because it is also borrowed as mutable
  --> src/main.rs:10:17
   |
9  |     let mut orig_conns = conns.get_mut(&start).unwrap();
   |                          ----- mutable borrow occurs here
10 |     let pipes = conns.get(&num).unwrap();
   |                 ^^^^^ immutable borrow occurs here
...
19 | }
   | - mutable borrow ends here

error[E0499]: cannot borrow `*conns` as mutable more than once at a time
  --> src/main.rs:16:46
   |
9  |     let mut orig_conns = conns.get_mut(&start).unwrap();
   |                          ----- first mutable borrow occurs here
...
16 |             populate_connections(start, num, conns, ancs);
   |                                              ^^^^^ second mutable borrow occurs here
...
19 | }
   | - first borrow ends here

我不知道如何让它工作.一开始,我试图将两个 HashSet 存储在 HashMap(orig_connspipes)中.

I don't know how to make it work. At the beginning, I'm trying to get two HashSets stored in a HashMap (orig_conns and pipes).

Rust 不会让我同时拥有可变和不可变变量.我有点困惑,因为这将是完全不同的对象,但我想如果 &start == &num,那么我会有两个不同的引用对象(一个可变,一个不可变).

Rust won't let me have both mutable and immutable variables at the same time. I'm confused a bit because this will be completely different objects but I guess if &start == &num, then I would have two different references to the same object (one mutable, one immutable).

没关系,但是我怎样才能做到这一点?我想遍历一个 HashSet 并读取和修改另一个.让我们假设它们不是相同的 HashSet.

Thats ok, but then how can I achieve this? I want to iterate over one HashSet and read and modify other one. Let's assume that they won't be the same HashSet.

推荐答案

如果您可以更改数据类型和函数签名,则可以使用 RefCell 来创建 内部可变性:

If you can change your datatypes and your function signature, you can use a RefCell to create interior mutability:

use std::cell::RefCell;
use std::collections::{HashMap, HashSet};

fn populate_connections(
    start: i32,
    num: i32,
    conns: &HashMap<i32, RefCell<HashSet<i32>>>,
    ancs: &mut HashSet<i32>,
) {
    let mut orig_conns = conns.get(&start).unwrap().borrow_mut();
    let pipes = conns.get(&num).unwrap().borrow();

    for pipe in pipes.iter() {
        if !ancs.contains(pipe) && !orig_conns.contains(pipe) {
            ancs.insert(*pipe);
            orig_conns.insert(*pipe);
            populate_connections(start, num, conns, ancs);
        }
    }
}

fn main() {}

请注意,如果 start == num,线程将恐慌,因为这是尝试对同一 HashSet 进行可变和不可变访问.

Note that if start == num, the thread will panic because this is an attempt to have both mutable and immutable access to the same HashSet.

根据您的确切数据和代码需求,您还可以使用诸如 Cell原子.它们比 RefCell 具有更低的内存开销,并且对代码生成的影响很小.

Depending on your exact data and code needs, you can also use types like Cell or one of the atomics. These have lower memory overhead than a RefCell and only a small effect on codegen.

在多线程情况下,您可能希望使用 MutexRwLock.

In multithreaded cases, you may wish to use a Mutex or RwLock.

这篇关于从同一个 HashMap 中借用两个可变值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-21 14:16