有没有办法为特定的 HashSet 或 HashMap 覆盖类型的相等性和哈希函数?

Is there a way to override the equality and hash functions of a type for a particular HashSet or HashMap?

我有一个 User 结构:

struct User {
    id: i32,
    email: String,
    // ...
}

在我的代码的一部分中,我想通过数据库 ID 获取唯一用户,但在另一段代码中,我想通过电子邮件地址获取唯一用户。我曾在系统上工作过,用户使用 LDAP CN、电子邮件等映射到外部系统帐户,并且在某些情况下能够通过不同的 ID 映射用户非常有用。

在 .NET 中,您可以传入 IEqualityComparer interface to override equals/hash for a particular Dictionary. In C++, the unordered_map class 具有散列和 eq 函数的通用参数。在 Java 中,我学会了只使用 Maps 而不是 Sets 当我想获得键控某些东西的唯一值时,但这可能很尴尬,尤其是对于复合键。

老实说,这是一种非常罕见的情况,并且总是有使用映射而不是集合或使用自己的 Hash/Eq impl 块创建包装器结构的解决方法。我只是好奇在 Rust 中是否有一种我还不知道的更简单的方法来做到这一点。

使用一个或多个 newtypes 以及您想要的相等性和散列的特定定义:

use std::hash::{Hash, Hasher};

struct ById(User);

impl Hash for ById {
    fn hash<H>(&self, h: &mut H)
    where
        H: Hasher,
    {
        self.0.id.hash(h)
    }
}

impl PartialEq for ById {
    fn eq(&self, other: &Self) -> bool {
        self.0.id == other.0.id
    }
}

impl Eq for ById {}
fn example(k: User, v: i32) {
    let mut h = std::collections::HashMap::new();
    h.insert(ById(k), v);
}

Do I need to use .0 to get at the underlying User when I pull ByIds out of the map?

是的。

Is there any magic to implicitly convert to the underlying User?

没有

I might be better off implementing Deref or something.

另请参阅:

  • How to use a struct's member as its own key when inserting the struct into a map without duplicating it?