PartialEq 和 PartialOrd 实现不返回正确的输出

tur*_*tle 1 rust

我已经为我的结构实现了PartialEqand PartialOrd,所以我可以BTreeSet使用一些自定义逻辑创建这些结构的 s:如果结构中的名称字段等于另一个结构的名称字段,则结构相等。当我查找一个结构体是否在这个集合中时,它只在整个结构体在集合中而不仅仅是名称字段时才返回 true。我该如何解决这个问题,以便两个断言都返回 true?

游乐场链接

use std::cmp::Ordering;
use std::collections::BTreeSet;


#[derive(Debug, Eq, Hash, Ord)]
struct Obj {
    name: String,
    count: i64,
}

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

impl PartialOrd for Obj {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.name.cmp(&other.name))
    }
}

fn vec_to_set(v: &[&str]) -> BTreeSet<Obj> {
    let hs: BTreeSet<Obj> = v
        .iter()
        .map(|d| {
            let mut count = 1;
            if d.to_string() == "C".to_string() {
                count = 2;
            };

            Obj {
                name: d.to_string(),
                count,
            }
        })
        .collect();
    hs
}

fn main() {
    let v = vec!["A", "B", "C", "A"];

    let hs = vec_to_set(&v);
    let t1 = Obj {
        name: "A".to_string(),
        count: 1,
    };
    let t2 = Obj {
        name: "A".to_string(),
        count: 10,
    };
    assert!(hs.contains(&t1));  // true
    assert!(hs.contains(&t2));  // false
}
Run Code Online (Sandbox Code Playgroud)

mca*_*ton 5

您不能手动实现PartialOrdPartialEq和派生Ord。不同的实现必须相互一致,默认生成的Ord实现与您手动实现的不同。

如果你替换#[derive(Ord)]

impl Ord for Obj {
    fn cmp(&self, other: &Self) -> Ordering {
        self.name.cmp(&other.name)
    }
}
Run Code Online (Sandbox Code Playgroud)

您的程序按预期工作。

然而,您可以在派生Eq时派生PartialEq,因为Eq它只是一个标记特征,所以它的派生实现不能与您的实现相矛盾。


的派生实现Hash 与 的手动实现不一致PartialEqBTreeSet不使用Hash, butHashMapHashSetdo ,并且他们也会对派生的Hashimpl行为不端。