How can I convince the borrow checker to allow me to cache values?

北战南征 提交于 2020-01-11 10:21:48

问题


The borrow checker beat me:

use std::collections::HashMap;

struct Cache {
    cache: Vec<HashMap<String, String>>,
}

impl Cache {
    fn get(&mut self, index: usize, key: String) -> String {
        let mut cache = &mut self.cache[index];
        match cache.get(&key) {
            Some(r) => {
                return r.clone();
            }
            None => {
                let r = "foo".to_string(); // something smart here
                cache.insert(key, r.clone());
                return r;
            }
        }
    }
}

What I get:

error[E0502]: cannot borrow `*cache` as mutable because it is also borrowed as immutable
  --> src/main.rs:16:17
   |
10 |         match cache.get(&key) {
   |               ----- immutable borrow occurs here
...
16 |                 cache.insert(key, r.clone());
   |                 ^^^^^ mutable borrow occurs here
...
19 |         }
   |         - immutable borrow ends here

How can I rewrite my code so that it compiles?


回答1:


Another approach is to use the entry interface. The only downside with this approach is that it (currently) doesn't use the BorrowFrom infrastructure that the get method uses, which makes it less flexible. In your case, that isn't a problem since get takes an owned key. The advantage of entry is that it only does one hash lookup, whereas using get forces you to do two lookups.

use std::collections::HashMap;

struct Cache {
    cache: Vec<HashMap<String, String>>,
}

impl Cache {
    fn get(&mut self, index: usize, key: String) -> String {
        self.cache[index]
            .entry(key)
            .or_insert_with(|| "foo".to_string())
            .clone()
    }
}



回答2:


The borrow checker sees cache.get as an immutable borrow, despite the fact that it is returning None. The easiest way to change your code is to move the insert out of the match, e.g.:

use std::collections::HashMap;

struct Cache {
    cache: Vec<HashMap<String, String>>,
}

impl Cache {
    fn get(&mut self, index: usize, key: String) -> String {
        let mut cache = &mut self.cache[index];
        match cache.get(&key) {
            Some(r) => {
                return r.clone();
            }
            None => (),
        }
        let r = "foo".to_string(); // something smart here
        cache.insert(key, r.clone());
        return r;
    }
}


来源:https://stackoverflow.com/questions/27648634/how-can-i-convince-the-borrow-checker-to-allow-me-to-cache-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!