使用Rust解除引用运算符&* vs * with Self?

问题描述 投票:2回答:2

我想编写一个具有内存大小限制的LRU缓存,而不是std中的“对象数量”限制。在试图为自己弄清楚之后,我作弊并看着an existing implementation,我几乎明白了,但这阻止了我:

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) }
    }
}

这是我不明白的最后一次unsafe线。我使用HashMap作为底层结构,密钥与值一起存储,我希望哈希能够找到它。我将工作哈希键作为对真实密钥的引用,并提供HashPartialEq函数,以便HashMap可以找到并使用密钥进行分组。这很简单。

我明白我必须比较这两个PartialEq,所以我必须使用*self.k取消引用当前对象,所以为什么&*other.k为另一个对象?这就是我不明白的地方。为什么不只是*other.k?我不是只是解除引用两者所以我可以比较实际的密钥吗?

rust
2个回答
6
投票

我们想打电话给PartialEq::eq

trait PartialEq<Rhs = Self>
where
    Rhs: ?Sized,
{
    fn eq(&self, other: &Rhs) -> bool;
}

假设Rhs = SelfSelf = K的默认实现,我们需要最终得到两个&K类型

  1. other.k*const K类型
  2. *other.kK类型
  3. &*other.k&K类型

这很有希望有意义。

  1. self.k*const K类型
  2. *self.kK类型

缺少他们被召唤的method calls are allowed to automatically reference the value的那件作品。这就是为什么参考和值没有明确的语法,就像在C或C ++中那样(foo.bar() vs foo->bar())。

因此,K会自动引用以获得&K,从而实现签名。


2
投票
impl<K: PartialEq> PartialEq for LruKeyRef<K> {
    fn eq(&self, other: &LruKeyRef<K>) -> bool {
        unsafe { (*self.k).eq(&*other.k) }
    }
}

在典型情况下,我们可以调用&self的方法,只需要引用该对象。此外,还隐式强制对该对象的引用链。也就是说,我们可以写:

let a: &str = "I'm a static string";
assert_eq!(str.len(), 19);
assert_eq!((&&&&str).len(), 19);

但是,在你的情况下,我们从一个指针开始,必须在不安全的范围内明确地取消引用。以下是所有相关表达式的类型:

self.k : *const K
(*self.k) : K
other.k : *const K
&*other.k : &K

由于equals对其右手成员进行了参考,我们必须将其作为参考。与C ++不同,您不能仅仅将左值作为引用传递而不使此引用传递显式,也不能将右值传递给const引用。但是,您可以将&添加到文字中以获取对它的引用(foo(&5))。它只显示不对称,因为(在某种程度上)self.k是调用者,other.k是被调用者。

© www.soinside.com 2019 - 2024. All rights reserved.