如何在插入“HashMap”后立即获得对键和值的引用?

时间:2017-04-28 13:28:26

标签: rust

use std::collections::HashMap;
use std::collections::hash_map::Entry::*;

fn hook(k: &str, v: &str) {}

fn tt(k: String, v: String) -> Option<String> {
    let mut a: HashMap<String, String> = HashMap::new();
    match a.entry(k) {
        Occupied(mut occupied) => {
            let old = occupied.insert(v);
            //hook(&k, &old);
            Some(old)
        }
        Vacant(vacant) => {
            let v = vacant.insert(v);
            let k = vacant.key(); // Why doesn't it work?
            //hook(&k, v);
            None
        }
    }
}

我想在将密钥插入hook后立即致电HashMap。我似乎必须使用Entry。但是,我无法在vacant.key()之后立即致电vacant.insert

1 个答案:

答案 0 :(得分:3)

TL; DR:你不能(现在?)

编译器告诉你它为什么不起作用。不要犹豫,阅读Rust编译器消息;它们并不可怕,并且付出了很多努力!

error[E0382]: use of moved value: `vacant`
  --> src/main.rs:16:21
   |
15 |             let v = vacant.insert(v);
   |                     ------ value moved here
16 |             let k = vacant.key();
   |                     ^^^^^^ value used here after move
   |
   = note: move occurs because `vacant` has type `std::collections::hash_map::VacantEntry<'_, std::string::String, std::string::String>`, which does not implement the `Copy` trait

这只是普通的Rust代码。 VacantEntry::insert按值消耗self,返回对插入值的引用:

fn insert(self, value: V) -> &'a mut V

over 100 other question/answer pairs询问此错误消息,因此我假设您已经阅读了足够多的内容以了解此问题;这就是为什么我们毕竟回答有关Stack Overflow的问题的原因!

所以为什么是这样的?这更难回答。当您插入HashMap时,它将获得密钥和值的所有权。当您使用entry API时,会有一个中间步骤 - 您已获得该条目密钥的所有权。条目具有对HashMap的可变引用; a&#34;书签&#34;价值在哪里。

当缺少值然后插入值时,密钥将从条目转移到HashMap。这意味着对条目内的键的引用将无效。这就是为什么你不能对两条线重新排序的原因。

然而,考虑到它更深一点,从insert返回的在插入值后引用基础HashMap。我无法看到任何阻止添加函数的原因,该函数返回对键和值的引用。但是,这样的功能现在还不存在。

另见How can I keep a reference to a key after it has been inserted into a HashMap?

我非常确定在这个的情况下你不需要这个功能。

如果您想为 new 值调用它,请在插入之前完成所有这些操作:

hook(&k, &v);
a.insert(k, v);

如果您只想为旧值执行此操作,则在以前没有值时不执行任何操作,您可以:

Occupied(mut occupied) => {
    let old = occupied.insert(v);
    hook(occupied.key(), &old);
    Some(old)
}

如果您想使用值调用挂钩(如果有),并且如果插入值(这似乎不一致),则可以将其称为添加之前,hook函数将更明智,因为参数只是引用:

Vacant(vacant) => {
    hook(vacant.key(), &v);
    let v = vacant.insert(v);
    None
}