Rust中实现Eq trait的作用是什么?哪些场景下实现Eq会有差异?
为什么要给Rust类型实现
Eq trait?哪些场景下实现Eq会有差异? 先看这段代码:不管加不加impl Eq for S {},输出都是false和false,那Eq到底有啥用?
fn main() { struct S(i32); impl PartialEq for S { fn eq(&self, _: &Self) -> bool { return false; } } impl Eq for S {} // 这一行加不加,结果没区别? let s1 = S(3); let s2 = S(4); println!("{}", s1 == s1); println!("{}", s1 == s2); }
为啥要实现Eq?
Eq是PartialEq的子trait,它本质是个语义标记:告诉编译器和其他开发者,这个类型的相等判断是个完整的等价关系——满足自反(a == a必为true)、对称(a == b则b == a)、传递(a == b且b == c则a == c)。
你的例子里故意写了个违反自反性的PartialEq,但这是不符合常规预期的。实现Eq相当于立下一个契约:我的类型不会搞这种特殊情况,相等判断是符合直觉的。
哪些场景下Eq会产生实际差异?
API约束要求:很多标准库和第三方库的API明确要求泛型参数实现
Eq。比如:HashMap<K, V>的部分方法,或者把类型当HashSet元素时,Hashtrait必须和Eq一起实现——因为哈希的逻辑是“相等的元素必须有相同哈希值”,Eq的自反性能保证这一点的合理性。BTreeSet<T>的插入、查找逻辑依赖元素的相等关系是等价关系,所以要求T: Eq。
要是你的类型只实现PartialEq,用这些API直接编译报错。
避免语义混淆:如果你的类型实现了
Eq,其他开发者一看就知道:这个类型的==是正常的,不会出现a != a这种离谱情况。要是只实现PartialEq,别人就得小心你的相等逻辑是不是有特殊处理(比如浮点数的NaN,它和自己不等,所以f32/f64只实现PartialEq不实现Eq)。与其他trait的联动:比如
Ord(全序trait)要求实现Eq,因为全序关系里的相等必须是等价关系;还有一些自定义trait可能会把Eq作为约束,确保逻辑的正确性。测试与断言的合理性:虽然
assert_eq!宏只要求PartialEq,但如果你的类型实现了Eq,写测试的人会更放心——毕竟没人会写assert_eq!(a, a)却担心失败,但如果你的PartialEq违反自反性,这个断言就会炸,而实现Eq相当于提前规避了这种风险。
内容的提问来源于stack exchange,提问作者TSK
相关产品推荐
相关产品推荐

