交换 HashMap 的两个条目

swapping two entries of a HashMap

我有一个简单的HashMap;说 HashMap<char, char>.

有没有办法使用 std::mem::swap(或任何其他方法)交换此哈希图中的两个元素?

当然有一种使用 get and then replace them with insert 获取值的简单方法 - 但这会触发哈希器两次(一次用于获取然后用于插入)我正在寻找一种方法来回避第二次哈希调用(更多的是出于好奇而不是性能)。

我尝试的是这个(在几个版本中;none 其中有效 - 正如评论中所说:entry 不会做我期望的,即使我通过了编译器):

use std::collections::HashMap;
use std::mem::swap;

let mut hash_map: HashMap<char, char> = HashMap::default();
hash_map.insert('A', 'Z');
hash_map.insert('B', 'Y');

swap(&mut hash_map.entry('A'), &mut hash_map.entry('B'));

现在编译器报错了(我明白为什么会报错)

error[E0499]: cannot borrow `hash_map` as mutable more than once at a time
   --> tests.rs:103:42
    |
103 |      swap(&mut hash_map.entry('A'), &mut hash_map.entry('B'));
    |      ----      --------                  ^^^^^^^^ second mutable borrow occurs here
    |      |         |
    |      |         first mutable borrow occurs here
    |      first borrow later used by call

同样,以这种方式获取两个值也会以大致相同的方式失败:

let mut a_val = hash_map.get_mut(&'A').expect("failed to get A value");
let mut b_val = hash_map.get_mut(&'B').expect("failed to get B value");
swap(&mut a_val, &mut b_val);

有没有办法简单地交换 HashMap 的两个条目?

我看不到任何安全的方法:

use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();
    map.insert('A', 'Z');
    map.insert('B', 'Y');

    let a = map.get_mut(&'A').unwrap() as *mut char;
    let b = map.get_mut(&'B').unwrap() as *mut char;
    unsafe {
        std::ptr::swap(a, b);
    }

    assert_eq!(map.get(&'A'), Some(&'Y'));
    assert_eq!(map.get(&'B'), Some(&'Z'));
}

我可以想到一种完全安全的方法来安全地执行此操作,但它的效率非常低:您想要的是获得两个 &mut 值,这意味着 borrowck 需要知道它们是不重叠的。缺少 split_mut 中的内置函数(或专门处理的集合),我看到的唯一方法是可变地迭代整个集合,保留对您感兴趣的项目的引用,然后交换:

    let mut h = HashMap::new();
    h.insert("a", "a");
    h.insert("b", "b");

    let mut it = h.iter_mut();
    let e0 = it.next().unwrap();
    let e1 = it.next().unwrap();
    std::mem::swap(e0.1, e1.1);
    println!("{:?}", h);

它需要对映射进行线性遍历,直到找到要交换其值的条目。因此,即使这具有完全不散列的优点,edwardw 的答案可能更实用。