Entry::Occupied.get() returns 引用当前函数拥有的数据的值,即使 hashmap 应该拥有所有权
Entry::Occupied.get() returns a value referencing data owned by the current function even though hashmap should have the ownership
我的目标是实现对 rust book 第 13.1 章的 cacher struct 的建议改进,即创建一个采用函数并使用 memoization 来减少数量的结构给定函数的调用。为此,我创建了一个带有 HashMap
的结构
struct Cacher<T, U, V>
where T: Fn(&U) -> V, U: Eq + Hash
{
calculation: T,
map: HashMap<U,V>,
}
和两种方法,一种构造函数和一种负责记忆的方法。
impl<T, U, V> Cacher<T, U, V>
where T: Fn(&U) -> V, U: Eq + Hash
{
fn new(calculation: T) -> Cacher<T,U,V> {
Cacher {
calculation,
map: HashMap::new(),
}
}
fn value(&mut self, arg: U) -> &V {
match self.map.entry(arg){
Entry::Occupied(occEntry) => occEntry.get(),
Entry::Vacant(vacEntry) => {
let argRef = vacEntry.key();
let result = (self.calculation)(argRef);
vacEntry.insert(result)
}
}
}
}
我使用了 Entry 枚举,因为我没有找到更好的方法来确定 HashMap 是否包含一个键和 -如果没有 - 计算值并将其插入 HashMap 并返回对它的引用。
如果我想编译上面的代码,我会得到一个错误,指出 occEntry 被它的 .get() 借用了方法(这对我来说很好)和 .get() "returns a value referencing data owned by the current function".
我的理解是,编译器认为 occEntry.get() 所引用的值属于函数 value(.. .)。但是我不应该得到 HashMap 所拥有的类型 V 的值的引用吗?编译器是否因为该值归函数所有并在短时间内保存为 result 而感到困惑?
let result = (self.calculation)(argRef);
vacEntry.insert(result)
请注意,需要暂时保存结果,因为insert方法消耗了key,argRef不再有效.此外,我承认 value 的签名可能存在问题(参见 Mutable borrow from HashMap and lifetime elision),但我试图避免 Copy Trait Bound。
为了快速重现问题,我附加了必要的 use 语句。感谢您的帮助。
use std::collections::HashMap;
use std::cmp::Eq;
use std::hash::Hash;
use std::collections::hash_map::{OccupiedEntry, VacantEntry, Entry};
我们来看看OccupiedEntry::get()
的签名:
pub fn get(&self) -> &V
这个签名告诉我们的是,从 OccupiedEntry
获得的引用只能与 OccupiedEntry
本身一样长。然而,OccupiedEntry
是一个局部变量,因此当函数 returns.
时它被删除
我们想要的是一个生命周期绑定到HashMap
生命周期的引用。两者 Entry
and OccupiedEntry
have a lifetime parameter ('a
), which is linked to the &mut self
parameter in HashMap::entry
. We need a method on OccupiedEntry
that returns a &'a V
. There's no such method, but there's one that returns a '&a mut V
: into_mut
。可变引用可以隐式强制转换为共享引用,因此要使您的方法编译,我们需要做的就是将 get()
替换为 into_mut()
.
fn value(&mut self, arg: U) -> &V {
match self.map.entry(arg) {
Entry::Occupied(occ_entry) => occ_entry.into_mut(),
Entry::Vacant(vac_entry) => {
let arg_ref = vac_entry.key();
let result = (self.calculation)(arg_ref);
vac_entry.insert(result)
}
}
}
我的目标是实现对 rust book 第 13.1 章的 cacher struct 的建议改进,即创建一个采用函数并使用 memoization 来减少数量的结构给定函数的调用。为此,我创建了一个带有 HashMap
的结构struct Cacher<T, U, V>
where T: Fn(&U) -> V, U: Eq + Hash
{
calculation: T,
map: HashMap<U,V>,
}
和两种方法,一种构造函数和一种负责记忆的方法。
impl<T, U, V> Cacher<T, U, V>
where T: Fn(&U) -> V, U: Eq + Hash
{
fn new(calculation: T) -> Cacher<T,U,V> {
Cacher {
calculation,
map: HashMap::new(),
}
}
fn value(&mut self, arg: U) -> &V {
match self.map.entry(arg){
Entry::Occupied(occEntry) => occEntry.get(),
Entry::Vacant(vacEntry) => {
let argRef = vacEntry.key();
let result = (self.calculation)(argRef);
vacEntry.insert(result)
}
}
}
}
我使用了 Entry 枚举,因为我没有找到更好的方法来确定 HashMap 是否包含一个键和 -如果没有 - 计算值并将其插入 HashMap 并返回对它的引用。
如果我想编译上面的代码,我会得到一个错误,指出 occEntry 被它的 .get() 借用了方法(这对我来说很好)和 .get() "returns a value referencing data owned by the current function".
我的理解是,编译器认为 occEntry.get() 所引用的值属于函数 value(.. .)。但是我不应该得到 HashMap 所拥有的类型 V 的值的引用吗?编译器是否因为该值归函数所有并在短时间内保存为 result 而感到困惑?
let result = (self.calculation)(argRef);
vacEntry.insert(result)
请注意,需要暂时保存结果,因为insert方法消耗了key,argRef不再有效.此外,我承认 value 的签名可能存在问题(参见 Mutable borrow from HashMap and lifetime elision),但我试图避免 Copy Trait Bound。
为了快速重现问题,我附加了必要的 use 语句。感谢您的帮助。
use std::collections::HashMap;
use std::cmp::Eq;
use std::hash::Hash;
use std::collections::hash_map::{OccupiedEntry, VacantEntry, Entry};
我们来看看OccupiedEntry::get()
的签名:
pub fn get(&self) -> &V
这个签名告诉我们的是,从 OccupiedEntry
获得的引用只能与 OccupiedEntry
本身一样长。然而,OccupiedEntry
是一个局部变量,因此当函数 returns.
我们想要的是一个生命周期绑定到HashMap
生命周期的引用。两者 Entry
and OccupiedEntry
have a lifetime parameter ('a
), which is linked to the &mut self
parameter in HashMap::entry
. We need a method on OccupiedEntry
that returns a &'a V
. There's no such method, but there's one that returns a '&a mut V
: into_mut
。可变引用可以隐式强制转换为共享引用,因此要使您的方法编译,我们需要做的就是将 get()
替换为 into_mut()
.
fn value(&mut self, arg: U) -> &V {
match self.map.entry(arg) {
Entry::Occupied(occ_entry) => occ_entry.into_mut(),
Entry::Vacant(vac_entry) => {
let arg_ref = vac_entry.key();
let result = (self.calculation)(arg_ref);
vac_entry.insert(result)
}
}
}