借用尝试缓存的问题

时间:2014-08-07 18:55:41

标签: rust

以下代码段以3种方式执行相同的操作。

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没有编译,给出以下错误:

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。 t end因为self返回对{{1}}中包含的内容的引用。这是否正确?

如何实现在自我中查找可变缓存中的值并将引用传递给另一个自我方法的预期目标?

2 个答案:

答案 0 :(得分:2)

Rust目前还没有很好地处理这种缓存。

最好的解决方案是完全避免这个问题。 show_impl真的需要成为Foo的方法吗?如果没有,您可以定义新特征并为String实施。例如:

trait ShowImpl: std::fmt::Display {
    fn show_impl(&self) {
        println!("{}", self);
    }
}

impl ShowImpl for String {}

然后只需在字符串show_impl

上调用self.get_cached(key).show_impl();即可

以下是使用UnsafeCell的解决方案。我不确定它是否正常工作。虽然它编译,但使用不安全的代码意味着编译器不再能保证安全。

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() {}

答案 1 :(得分:0)

您可以尝试在&mut self上添加show_impl,如

...
fn show_impl(&self, what: &String)  
...

所以它不会变得混乱。