I want to write an LRU Cache with a memory size limitation rather than the "number of objects" limitation in std. After trying to figure it out for myself, I cheated and looked at an existing implementation, and I almost understand it, but this stops me:
struct KeyRef<K> {
k: *const K,
}
impl<K: Hash> Hash for LruKeyRef<K> {
fn hash<H: Hasher>(&self, state: &mut H) {
unsafe { (*self.k).hash(state) }
}
}
impl<K: PartialEq> PartialEq for LruKeyRef<K> {
fn eq(&self, other: &LruKeyRef<K>) -> bool {
unsafe { (*self.k).eq(&*other.k) }
}
}
It's that last unsafe
line that I don't understand. I'm using a HashMap
as the underlying structure, the key is stored with the value, and I want the hasher to be able to find it. I make the working hash key a reference to the real key and provide Hash
and PartialEq
functions such that the HashMap
can find and use the key for bucketing purposes. That's easy.
I understand then that I have to compare the two for PartialEq
, and so it makes sense to me that I have to use *self.k
to dereference the current object, so why &*other.k
for the other object? That's what I don't understand. Why isn't it just *other.k
? Aren't I just dereferencing both so I can compare the actual keys?
We wish to call PartialEq::eq
:
trait PartialEq<Rhs = Self>
where
Rhs: ?Sized,
{
fn eq(&self, other: &Rhs) -> bool;
}
Assuming the default implementation where Rhs
= Self
and Self
= K
, we need to end up with two &K
types
other.k
is of type *const K
*other.k
is of type K
&*other.k
is of type &K
This much should hopefully make sense.
self.k
is of type *const K
*self.k
is of type K
The piece that's missing that that method calls are allowed to automatically reference the value they are called on. This is why there's no distinct syntax for a reference and a value, as there would be in C or C++ (foo.bar()
vs foo->bar()
).
Thus, the K
is automatically referenced to get &K
, fulfilling the signature.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With