尝试缓存的借用问题 [英] Borrowing issues with attempted caching
问题描述
以下代码片段以 3 种方式执行相同的操作.
The following code snippet does the same things in 3 ways.
use std::collections::HashMap;
struct Foo {
cache: HashMap<String, String>,
}
impl Foo {
fn get_cached(&mut self, key: &String) -> &String {
if !self.cache.contains_key(key) {
self.cache.insert(key.clone(), String::from("default"));
}
self.cache.get(key).unwrap()
}
fn show_impl(&self, what: &String) {
println!("{}", what);
}
pub fn show1(&mut self, key: &String) {
println!("{}", self.get_cached(key));
}
pub fn show2(&mut self, key: &String) {
if !self.cache.contains_key(key) {
self.cache.insert(key.clone(), String::from("default"));
}
self.show_impl(self.cache.get(key).unwrap());
}
// This does not compile
pub fn show3(&mut self, key: &String) {
self.show_impl(self.get_cached(key));
}
}
fn main() {}
show3
无法编译,出现以下错误:
show3
doesn't compile, giving the following error:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:28:24
|
28 | self.show_impl(self.get_cached(key));
| ---- ^^^^ - immutable borrow ends here
| | |
| | mutable borrow occurs here
| immutable borrow occurs here
据我所知,show3
的问题不在于可变性,而是双重借用:self
的借用被交给 get_cached
不会结束,因为 get_cached
返回对 self
中包含的内容的引用.这甚至正确吗?
As far as I tell, the issue with show3
is not about mutability, but rather a double borrow: the borrow of self
is given away to get_cached
which doesn't end because get_cached
returns a reference to something contained in self
. Is this even correct?
如何实现在 self 的可变缓存中查找值并将引用传递给 self 的另一个方法的预期目标?
How can I accomplish my intended goal of looking up a value in a mutable cache in self and pass the reference to another method of self?
推荐答案
Rust 目前不能很好地处理这种缓存.
Rust doesn't handle this sort of caching well at the moment.
最好的解决方案是完全避免这个问题.show_impl
真的需要成为 Foo
的方法吗?如果没有,您可以定义一个新特征并为 String
实现它.例如:
The best solution is to avoid the problem altogether. Does show_impl
really need to be a method of Foo
? If not, you can define a new trait and implement it for String
. For example:
trait ShowImpl: std::fmt::Display {
fn show_impl(&self) {
println!("{}", self);
}
}
impl ShowImpl for String {}
然后在字符串上调用show_impl
:self.get_cached(key).show_impl();
这是一个使用 UnsafeCell
的解决方案.我不确定它是否正常工作.虽然它确实可以编译,但使用不安全的代码意味着编译器无法再保证安全.
Here is a solution that uses UnsafeCell
. I'm not sure if it works correctly. While it does compile, the use of unsafe code means the compiler can no longer guarantee safety.
use std::collections::HashMap;
use std::cell::UnsafeCell;
struct Foo {
cache: UnsafeCell<HashMap<String, String>>,
}
impl Foo {
fn get_cached(&self, key: &String) -> &String {
unsafe {
if !(*self.cache.get()).contains_key(key) {
(*self.cache.get()).insert(key.clone(), String::from("default"));
}
(*self.cache.get()).get(key).unwrap()
}
}
fn show_impl(&self, what: &String) {
println!("{}", what);
}
pub fn show1(&mut self, key: &String) {
println!("{}", self.get_cached(key));
}
pub fn show2(&mut self, key: &String) {
unsafe {
if !(*self.cache.get()).contains_key(key) {
(*self.cache.get()).insert(key.clone(), String::from("default"));
}
self.show_impl((*self.cache.get()).get(key).unwrap());
}
}
pub fn show3(&self, key: &String) {
self.show_impl(self.get_cached(key));
}
}
fn main() {}
这篇关于尝试缓存的借用问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!