如何为我自己的结构实现 Eq 和 Hash 以将它们用作 HashMap 键?

How to implement Eq and Hash for my own structs to use them as a HashMap key?

我有两个结构,AB,我想使用 HashMap<A, B>。我有一段这样的代码:

use std::collections::HashMap;

pub struct A {
    x: i32,
    y: i32,
    title: String,
}

pub struct B {
    a: u32,
    b: u32,
}

fn main() {
    let map = HashMap::new();
    map.insert(
        A {
            x: 10,
            y: 20,
            title: "test".to_string(),
        },
        B { a: 1, b: 2 },
    );
}

但是编译器给我这些错误:

error[E0277]: the trait bound `A: std::cmp::Eq` is not satisfied
  --> src/main.rs:16:9
   |
16 |     map.insert(
   |         ^^^^^^ the trait `std::cmp::Eq` is not implemented for `A`

error[E0277]: the trait bound `A: std::hash::Hash` is not satisfied
  --> src/main.rs:16:9
   |
16 |     map.insert(
   |         ^^^^^^ the trait `std::hash::Hash` is not implemented for `A`

我知道我必须实现这些特征,但是在网上搜索了几个小时后,我没有找到任何关于实现它们的信息。

我的实际代码比较复杂,我的结构包含其他结构(我已经编辑了代码)。

我已经实现了 Hash 特征:

impl std::hash::Hash for A {
    fn hash<H>(&self, state: &mut H)
    where
        H: std::hash::Hasher,
    {
        state.write_i32(self.x);
        state.finish();
    }
}

我还为 PartialEq 做了一个实现:

impl PartialEq for A {
    fn eq(&self, other: &A) -> bool {
        self.x == other.x
    }
}

但是编译器继续报错,这次是关于 Eq:

error[E0277]: the trait bound `A: std::cmp::Eq` is not satisfied
  --> src/main.rs:16:9
   |
16 |     map.insert(
   |         ^^^^^^ the trait `std::cmp::Eq` is not implemented for `A`

如何实施 Eq?为什么文档中没有实现?

您可以让编译器为您派生这些实例,方法是在结构声明之前插入以下内容:

#[derive(PartialEq, Eq, Hash)]
pub struct A {
    // ...
}

您也可以手动实施它们。如果你想这样做,你应该阅读 traits, Eq and Hash.

上的文档

Eq就是我们所说的marker trait:它本身没有方法,它只是程序员表达struct验证某个属性的一种方式。你可以这样实现它:

impl Eq for Application {}

或者,在 Application 声明之上使用 #[derive(Eq)]

Eq 是受 PartialEq 约束的特征。这意味着您只能在也实现 PartialEq 的结构上实现它(这里就是这种情况)。通过实施 Eq,您承诺 PartialEq 的实施是自反的(请参阅文档了解其含义)。

这就是 Rust 文档所说的如何编写自己的 Hash 实现:

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

struct Person {
    id: u32,
    name: String,
    phone: u64,
}

impl Hash for Person {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.id.hash(state);
        self.phone.hash(state);
    }
}

来源:https://doc.rust-lang.org/std/hash/trait.Hash.html