尝试缓存的借用问题 [英] Borrowing issues with attempted caching

查看:50
本文介绍了尝试缓存的借用问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码片段以 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆