[rust-026]rust的Eq和PartialEq以及存储到HashMap遇到的Hash问题

实现了一个struct,然后new出两个实例,比较它们是否相等,会报错,形如:

struct Man{
    pub age: i32,
    pub name: String,
}


fn test_1(){
    let x1 = Man{
        age: 11,
        name: String::from("tim"),
    };

    let x2 = Man{
        age: 12,
        name: String::from("sam"),
    };

    assert_eq!(x1, x2);

}

fn main() {
    test_1();
}


/*
运行结果:
error[E0369]: binary operation `==` cannot be applied to type `Man`
  --> src/main.rs:18:5
   |
18 |     assert_eq!(x1, x2);
   |     ^^^^^^^^^^^^^^^^^^^
   |     |
   |     Man
   |     Man
   |
   = note: an implementation of `std::cmp::PartialEq` might be missing for `Man`
*/

这个报错,是没有实现PartialEq特质。

这个特质相关的文档在这里  https://doc.rust-lang.org/std/cmp/index.html

PartialEq文档在这里 https://doc.rust-lang.org/std/cmp/trait.PartialEq.html ,实现它即可,不报错了:

#[derive(Debug)]
struct Man{
    pub age: i32,
    pub name: String,
}

impl PartialEq for Man{
    fn eq(&self, other: &Self) -> bool {
        (self.age == other.age) && (self.name == other.name)
    }
}

fn test_1(){
    let x1 = Man{
        age: 11,
        name: String::from("tim"),
    };

    let x2 = Man{
        age: 12,
        name: String::from("sam"),
    };

    assert_eq!(x1, x2);

}

fn main() {
    test_1();
}

如果将实例加入到HashMap会报错,提示没有实现Eq和Hash特质:

use std::collections::HashMap;

#[derive(Debug)]
struct Man{
    pub age: i32,
    pub name: String,
}

impl PartialEq for Man{
    fn eq(&self, other: &Self) -> bool {
        (self.age == other.age) && (self.name == other.name)
    }
}

fn test_1(){
    let x1 = Man{
        age: 11,
        name: String::from("tim"),
    };

    let x2 = Man{
        age: 12,
        name: String::from("sam"),
    };

    let mut ahash = HashMap::new();
    ahash.insert(&x1, 1i32);

    assert_eq!(x1, x2);

}

fn main() {
    test_1();
}


/*
运行结果:
error[E0277]: the trait bound `Man: std::cmp::Eq` is not satisfied
  --> src/main.rs:27:11
   |
27 |     ahash.insert(&x1, 1i32);
   |           ^^^^^^ the trait `std::cmp::Eq` is not implemented for `Man`
   |
   = note: required because of the requirements on the impl of `std::cmp::Eq` for `&Man`

error[E0277]: the trait bound `Man: std::hash::Hash` is not satisfied
  --> src/main.rs:27:11
   |
27 |     ahash.insert(&x1, 1i32);
   |           ^^^^^^ the trait `std::hash::Hash` is not implemented for `Man`
   |
   = note: required because of the requirements on the impl of `std::hash::Hash` for `&Man`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0277`.

*/

根据Eq的文档 https://doc.rust-lang.org/std/cmp/trait.Eq.html  可知,Eq是一个空的特质,没有具体方法,只是为编译器提供一个信息:这个对象会用到Eq操作。

HashMap,肯定需要Key实现了Hash。Hash特质的文档在https://doc.rust-lang.org/std/hash/trait.Hash.html 。如果struct的每个成员所属struct已经实现了Hash特质,只要#[derive(Hash)]即可,否认需要手动实现Hash,这里选择前者。

use std::collections::HashMap;

#[derive(Debug, Hash)]
struct Man{
    pub age: i32,
    pub name: String,
}

impl PartialEq for Man{
    fn eq(&self, other: &Self) -> bool {
        (self.age == other.age) && (self.name == other.name)
    }
}

impl Eq for Man{}

fn test_1(){
    let x1 = Man{
        age: 11,
        name: String::from("tim"),
    };

    let x2 = Man{
        age: 12,
        name: String::from("sam"),
    };

    let x3 = Man{
        age: 11,
        name: String::from("tim"),
    };

    let mut ahash = HashMap::new();
    ahash.insert(&x1, 1i32);

    assert_eq!(x1, x3);
    assert_eq!(x1, x2);

}

fn main() {
    test_1();
}

前面说过Eq特质是没有方法的,空的。通常的用法是,同时实现Eq和Hash特质,如果两个实例的Hash值相等,那么它们也就是相等的。通过Hash特质实现Eq特质。

那么,Eq和PartialEq有啥区别?Eq,从意义上而言,表示两个实例完全相等,这比较复杂,比如深度嵌套struct不好解决,干脆空掉。PartialEq的字面意思是部分相等,也就是两个实例内部的若干成员相等即可,当然,实际实现可以随意操作,全部成员相等也没问题。

那么,把kv值添加到HashMap的时候,相同hash的key是同一个key,会有更替关系。

你可能感兴趣的:(rust,rust)