【发布时间】:2020-02-07 08:41:44
【问题描述】:
在chapter 13 of the Rust book 中,您实现了一个Cacher 结构用于延迟初始化,以演示闭包和函数式编程的使用。作为练习,他们鼓励读者尝试创建一个通用的Cacher,它可以存储多个值。为此,他们建议使用Hashmap。
尝试修改缓存器以保存哈希映射而不是单个值。哈希映射的键将是传入的 arg 值,哈希映射的值将是对该键调用闭包的结果。 value 函数不会直接查看 self.value 是否具有 Some 或 None 值,而是会在 hash map 中查找 arg 并返回该值(如果存在)。如果不存在,缓存器将调用闭包并将结果值保存在与其 arg 值关联的哈希映射中。
当前 Cacher 实现的第二个问题是它只接受带有一个 u32 类型参数并返回 u32 的闭包。例如,我们可能希望缓存采用字符串切片并返回 usize 值的闭包的结果。要解决此问题,请尝试引入更多通用参数以增加缓存功能的灵活性。
为了解决这个练习,我使用了以下代码:
struct Cacher<T, K, V>
where T: Fn(K) -> V
{
calculation: T,
values: HashMap<K, V>,
}
impl<T, K, V> Cacher<T, K, V>
where T: Fn(K) -> V,
K: std::cmp::Eq + std::hash::Hash + Clone,
{
fn new(calculation: T) -> Cacher<T, K, V> {
Cacher {
calculation,
values: HashMap::new(),
}
}
fn value(&mut self, intensity: K) -> &V {
self.values.entry(intensity.clone()).or_insert((self.calculation)(intensity))
}
}
这段代码可以编译并运行,但由于(self.calculation)(intensity) 总是被执行,所以它不能作为正确的Cacher。即使条目存在。我从文档和示例中了解到,Entry::or_insert 函数仅在Entry 不存在时才会执行。
我知道问题 Is it possible to use a single generic for both key and value of a HashMap? 中练习的解决方案,但我想知道是否可以按照我目前的方式解决问题。
编辑:如评论中所述:or_insert_with 不能解决问题。尝试or_insert_with(|| (self.calculation)(intensity.clone())) 时出现以下错误error[E0502]: cannot borrow self as immutable because it is also borrowed as mutable。
【问题讨论】:
-
TL;DR:你试过
or_insert_with吗? -
我刚刚尝试了
or_insert_with(|| (self.calculation)(intensity.clone()))并收到以下错误:error[E0502]: cannot borrow `self` as immutable because it is also borrowed as mutable。or_insert和or_insert_with除了前者期望一个值而后者期望一个返回值的闭包之外,还有什么区别吗? -
哼,没错,你不能这样。
-
您只需要将对
calculation的引用存储在前一行的单独let语句中:let calculation = &self.calculation;。借用检查器足够聪明,可以看到self.calculation和self.values在同一范围内发生时不会重叠,但如果您只在闭包内使用self.calculation,它将触发对所有 @987654345 的借用@,确实与self.values重叠。 -
@SvenMarnach 非常感谢。解决方案是添加您提到的行并使用@justinas 建议使用
or_insert_with。
标签: rust