我的目标是在Rust书第13.1章中实现对cacher结构的建议改进,即创建一个结构体,它接受一个函数并使用记忆化技术来减少调用给定函数的次数。为了实现这一点,我创建了一个具有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()“返回引用当前函数拥有数据的值”。
我的理解是,编译器认为occEntry.get()所引用的值是由value(...)函数拥有的。但是,我不应该获取类型为V的值的引用,该引用由HashMap拥有吗?编译器是否因为该值被函数拥有并作为result短暂保存而感到困惑?
let result = (self.calculation)(argRef);
vacEntry.insert(result)
请注意,由于插入方法消耗了密钥,因此需要临时保存结果,这样argRef就不再有效。此外,我承认value的签名可能存在问题(请参见可变从HashMap中借用和生命周期省略),但我尝试避免Copy特征绑定。
为了快速重现问题,我附加了必要的use语句。感谢您的帮助。
use std::collections::HashMap;
use std::cmp::Eq;
use std::hash::Hash;
use std::collections::hash_map::{OccupiedEntry, VacantEntry, Entry};