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
。
答案 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
}