I'm trying to use a RwLock around a mutable struct, but I can't make it compile and I'm not sure why.
Here's a minimum code sample:
use std::sync::RwLock;
use lru::LruCache;
fn main() {
let mut cache: LruCache<String,String> = LruCache::new(100);
cache.put("test".to_string(), "test_value".to_string());
let lock_cache = RwLock::new(cache);
let rc = lock_cache.read();
let res = rc.unwrap().get("test");
assert_eq!(res.unwrap().as_str(), "test_value");
}
where LruCache
comes from an external Rust crate (but I don't think it has a specific role in the issue).
The compiler complains with this message:
error[E0596]: cannot borrow data in a dereference of `RwLockReadGuard<'_, LruCache<String, String>>` as mutable
--> tests/cache_test.rs:295:15
|
295 | let res = rc.unwrap().get("test");
| ^^^^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `RwLockReadGuard<'_, LruCache<String, String>>`
I checked the docs for RwLock
and while RwLockWriteGuard
does implement DerefMut
, RwLockReadGuard
does not.
I'm quite new to Rust so I'm pretty sure I'm doing something wrong. Is there a way I can workaround the DerefMut
is required but not implemented, compiler error?
EDIT I changed the code so that is easily executable from a main file.
LruCache::get
requires &mut self
, as per its signature (docs):
pub fn get<'a, Q>(&'a mut self, k: &Q) -> Option<&'a V>
This is because of the nature of LRU caches: in order to keep track which items were most recently used, the cache needs to modify (write) its state:
<...> Moves the key to the head of the LRU list if it exists.
even though you're doing a "read" operation.
So, in your case, RwLock
wins you nothing over Mutex
, as you have to acquire a write lock anyway. The simplest options are either to use a Mutex<LruCache<K, V>>
instead, or choose another way of caching.