问题
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