作为Rust book的一部分,我实现了带有泛型的Cacher
结构。 Cacher
包含两个字段:闭包calculation
和一个value
字段,它是一个HashMap
:
use std::{collections::HashMap, hash::Hash};
struct Cacher<T, U, V>
where
T: Fn(U) -> V,
U: Eq + Hash,
{
calculation: T,
value: 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,
value: HashMap::new(),
}
}
fn value(&mut self, arg: U) -> &V {
self.value
.entry(arg)
.or_insert_with(|| (self.calculation)(arg))
}
}
我正在努力使用Cacher::value
方法,该方法应执行以下操作:
如果value
HashMap
包含与提供的参数匹配的键,则返回相应的值。
如果value
HashMap
不包含与参数匹配的键,请执行Cacher
的{{1}}闭包。使用提供的参数作为键,将此关闭的结果保存在calculation
中。
我尝试了各种解决方案,这些解决方案总是导致可变借用和不可变借用之间的冲突。我不确定如何解决该问题。
HashMap
我遇到了编译时错误,因为error[E0502]: cannot borrow `self` as immutable because it is also borrowed as mutable
--> src/lib.rs:27:29
|
24 | fn value(&mut self, arg: U) -> &V {
| - let's call the lifetime of this reference `'1`
25 | self.value
| ----------
| |
| _________mutable borrow occurs here
| |
26 | | .entry(arg)
27 | | .or_insert_with(|| (self.calculation)(arg))
| |_____________________________^^__----__________________- returning this value requires that `self.value` is borrowed for `'1`
| | |
| | second borrow occurs due to use of `self` in closure
| immutable borrow occurs here
error[E0382]: use of moved value: `arg`
--> src/lib.rs:27:29
|
12 | impl<T, U, V> Cacher<T, U, V>
| - consider adding a `Copy` constraint to this type argument
...
24 | fn value(&mut self, arg: U) -> &V {
| --- move occurs because `arg` has type `U`, which does not implement the `Copy` trait
25 | self.value
26 | .entry(arg)
| --- value moved here
27 | .or_insert_with(|| (self.calculation)(arg))
| ^^ --- use occurs due to use in closure
| |
| value used here after move
是可变借项,而在self.value.entry().or_insert_with()
内的闭包中使用self
会触发不可变的借用。
由于我正在将or_insert_with()
的所有权传递给arg
并尝试在闭包内再次使用它,因此value方法也遇到了错误。我应该在这种方法中使用引用吗?如果可以,怎么办?
我从较高的角度理解了这些问题,但是我正在努力寻找解决方法。在尝试读取或写入entry()
value
时,我该怎么做以防止可变借用和不可变借用的混合使用?
解决方案
我定居的solution。
闭包签名更改为HashMap
,而Fn(&U) -> V
方法更改为:
value