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
}
}
}
Run Code Online (Sandbox Code Playgroud)
我想hook在将密钥插入HashMap. 看来我得用Entry. 但是,我无法vacant.key()在vacant.insert.
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
Run Code Online (Sandbox Code Playgroud)
这只是普通的 Rust 代码。VacantEntry::insert按值消费self,返回对插入值的引用:
fn insert(self, value: V) -> &'a mut V
Run Code Online (Sandbox Code Playgroud)
还有超过 100 个其他问题/答案对询问此错误消息,因此我假设您已经阅读了足够多的内容以理解该问题;这就是我们在 Stack Overflow 上回答问题的原因!
那么为什么会这样呢?这更难回答。当您插入 a 时HashMap,它会获取键和值的所有权。当您使用entryAPI 时,有一个中间步骤 - 您已授予该条目密钥的所有权。该条目还具有对 ; 的可变引用HashMap;价值所在的“书签”。
当值丢失然后插入一个值时,密钥将从条目传输到HashMap. 这意味着对条目内密钥的引用将无效。这就是为什么你不能重新排列这两行的原因。
然而,更深入地思考一下,插入值后,返回的值insert引用了底层的。HashMap我看不出有任何理由阻止添加返回对键和值的引用的函数。然而,现在这样的功能并不存在。
我很确定在这种情况下您不需要该功能。
如果您想为新值调用它,只需在插入之前执行所有这些操作:
hook(&k, &v);
a.insert(k, v);
Run Code Online (Sandbox Code Playgroud)
如果您只想对旧值执行此操作,在以前没有值时不执行任何操作,您可以:
Occupied(mut occupied) => {
let old = occupied.insert(v);
hook(occupied.key(), &old);
Some(old)
}
Run Code Online (Sandbox Code Playgroud)
如果你想用旧值(如果有)和新值(如果插入)调用钩子(这似乎不一致),你可以在添加之前调用它,该hook函数不会更明智,因为参数只是引用:
Vacant(vacant) => {
hook(vacant.key(), &v);
let v = vacant.insert(v);
None
}
Run Code Online (Sandbox Code Playgroud)