1. The Problem
Consider the following function where self.cache
is of type HashMap<String, BlockChain>
:
async fn get_index(&self) -> HttpResponse { let blockchain = self.cache.lock().unwrap().get("blockchain").unwrap(); let first_block = blockchain[0].clone(); let block_json = serde_json::to_string(&first_block).unwrap(); debug!("block_json {:?}", block_json); HttpResponse::Ok().json(block_json) }
Problem:
The reason is that:
self.cache.lock()
is aMutexGuard
object with life time'a
self.cache.lock().get
has signature:impl<K, V> HashMap<K, V> { pub fn get<'a, Q>(&'a self, k: &Q) -> Option<&'a V>
self.cache.lock().get("key").unwrap()
is a&BlockChain
object, i.e., a pointer- Pointer can never be moved, it will be copied whenever we assign it to another variable. Now
blockchain = self.cache.lock().get("key").unwrap()
is a copy of a pointer self.cache.lock()
is a temporary value, now it gets dropped at the end of the statement after;
self.cache.lock().get
is now borrowing a dropped value, hence crashed
Remark. By dropped we mean that the value has executed its drop
method implemented for the Drop
trait. Most of the time it is a cleanup process for freeing the memory, but it is not always true.
2. Solution
We simply move the temporary data to a local variable which has longer life span (so that the .get()
makes sense):
async fn get_index(&self) -> HttpResponse { let unlocked_cache = self.cache.lock().unwrap(); let blockchain = unlocked_cache.get("blockchain").unwrap(); let first_block = blockchain[0].clone(); let block_json = serde_json::to_string(&first_block).unwrap(); debug!("block_json {:?}", block_json); HttpResponse::Ok().json(block_json) }