I am trying to create a struct that memoizes a given function. However, I ended up needing to write code like this:
match self.cache.borrow_mut().entry(key) {
Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => {
let value = (self.transform)(e.key());
e.insert(value)
}
}
Ideally I would be able to use std::collections::hash_map::Entry::or_insert_with
like this:
let entry = self.cache.borrow_mut().entry(key);
entry.or_insert_with(|| (self.transform)(entry.key()));
However this doesn't compile because by the time we're in the closure, we've moved key
into entry()
, then moved entry
into or_insert_with()
so it's not available for the closure to use.
I propose adding a new method to fix this: or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> &'a mut V
. It works exactly the same as the or_insert_with
but gives the closure a reference to the key, similarly to the first block of code above. In fact adding this would compact it to:
self.cache.borrow_mut().entry(key).or_insert_with_key(&self.transform);
Here's a preliminary working implementation:
fn or_insert_with_key<'a, F: FnOnce(&K) -> V, K, V>(
entry: Entry<'a, K, V>,
default: F,
) -> &'a mut V {
match entry {
Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => {
let value = default(e.key());
e.insert(value)
}
}
}
// ...
or_insert_with_key(
self.cache.borrow_mut().entry(key),
&self.transform,
)