【问题标题】:How to iterate elements of a hashmap over themselves and have them be mutable?如何在自身上迭代哈希图的元素并使它们可变?
【发布时间】:2022-01-16 05:58:58
【问题描述】:

所以我有一个使用字符串作为键的哈希图,值是我自己的用户结构。这只是他们的名字和职位

pub struct User {
    name: String,
    x: i32,
    y: i32
}

现在我要做的是遍历名为 users 的 hashmap 并查看两个用户的位置是否彼此靠近,然后将它们分开。

for (key, userA) in self.users.iter_mut() {
    for (key, userB) in self.users.iter_mut() {
        // collision code would go in here
    }
}

这会导致一个问题,因为用户随后被借用了两倍的可变用户。我想通过使用互斥体来解决这个问题,

for (key, userA) in self.users.lock().unwrap().iter_mut() {
    for (key, userB) in self.users.lock().unwrap().iter_mut() {
        // collision code would go in here
    }
}

并且代码可以编译,但是由于第二个循环,当我实际将用户添加到地图时,它会导致运行时错误,因为如果我注释掉该循环,则代码运行没有问题。关于如何以不同方式编写此内容的任何想法?

【问题讨论】:

  • 为什么不进行不可变迭代(使用.iter() 而不是.iter_mut()),然后仅在需要更新时才进行可变借用?
  • 它抱怨它在循环开始时也被借用为不可变的,没有互斥锁。使用互斥锁在编译时很好,但据我了解,互斥锁会锁定循环中的第一个借用,这会破坏一切。
  • 也许您可以使用嵌套的不可变迭代收集密钥对,然后根据收集的密钥对更新相应的值。
  • 我现在看到了这个问题,这实际上有点棘手。最简单/性能最好的选项可能是multi_mut crate 之类的东西,但这似乎有点可疑。您可能最终需要将 hashmap 值包装在 CellRefCell 中并使用不可变迭代,除非 @Joe_Jingyu 的方法适合您的用例。
  • 您是否尝试克隆用户 HashMap? for (key, userA) in self.users.clone().iter_mut() { 然后for (key, userA) in self.users.iter_mut() { ```

标签: rust borrow-checker


【解决方案1】:

您可以分两个阶段执行此操作。首先你收集碰撞,然后解决它们。举个例子:

let mut collisions = Vec::new();
for (key_a, user_a) in self.users.iter() {
    for (key_b, user_b) in self.users.iter() {
        if key_a == key_b {
            continue;
        }

        if user_a.x == user_b.x && user_a.y == user_b.y {
            collisions.push((key_a, key_b));
        }
    }
}

for (key_a, key_b) in collisions {
    // Move users apart.
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-12
    • 2023-04-07
    • 2011-04-28
    • 1970-01-01
    • 2013-02-06
    • 1970-01-01
    • 2013-04-09
    相关资源
    最近更新 更多