写点什么

实践解析丨 Rust 内置 trait:PartialEq 和 Eq

发布于: 2021 年 03 月 23 日

​​​​​​​​​​​​摘要:Rust 在很多地方使用了 traits, 从非常浅显的操作符重载, 到 Send, Sync 这种非常微妙的特性。


本文分享自华为云社区《Rust 内置 trait 解析:PartialEq 和 Eq》,原文作者:debugzhang。

 

 Rust 在很多地方使用了 traits, 从非常浅显的操作符重载,到 Send, Sync 这种非常微妙的特性。一些 traits 是可以被自动派生的(你只需要写 #[derive(Copy, Clone, PartialEq, Eq, Debug,Default, Hash, ...)]就能得到一个神奇的实现, 它通常是对的。


PartialEq 和 Eq 这两个 Traits 的名称实际上来自于抽象代数中的等价关系和局部等价关系,实际上两者的区别仅有一点,即是否在相等比较中是否满足反身性(Reflexivity)。

PartialEq


/// [`eq`]: PartialEq::eq/// [`ne`]: PartialEq::ne#[lang = "eq"]#[stable(feature = "rust1", since = "1.0.0")]#[doc(alias = "==")]#[doc(alias = "!=")]#[rustc_on_unimplemented(    message = "can't compare `{Self}` with `{Rhs}`",    label = "no implementation for `{Self} == {Rhs}`")]pub trait PartialEq<Rhs: ?Sized = Self> {    /// This method tests for `self` and `other` values to be equal, and is used    /// by `==`.    #[must_use]    #[stable(feature = "rust1", since = "1.0.0")]    fn eq(&self, other: &Rhs) -> bool;
/// This method tests for `!=`. #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn ne(&self, other: &Rhs) -> bool { !self.eq(other) }}
复制代码


如果我们想比较某个类型的两个值 x 和 y 是否相等(不等),例如:x == y (x != y),那么我们就必须为类型实现 PartialEq Trait。


PartialEq 可使用 #[derive]来交由编译器实现,当一个 struct 在进行相等比较时,会对其中每一个字段进行比较;如果遇到枚举时,还会对枚举所拥有的数据进行比较。


我们也可以自己实现 PartialEq,实现时只需要实现判断是否相等的函数 fn eq(&self, other: &Self) -> bool ,Rust 会自动提供 fnne(&self, other: &Self) -> bool。例子如下:


enum BookFormat {    Paperback,    Hardback,    Ebook,}
struct Book { isbn: i32, format: BookFormat,}
impl PartialEq for Book { fn eq(&self, other: &Self) -> bool { self.isbn == other.isbn }}
复制代码

Eq


pub trait Eq: PartialEq<Self> {    // this method is used solely by #[deriving] to assert    // that every component of a type implements #[deriving]    // itself, the current deriving infrastructure means doing this    // assertion without using a method on this trait is nearly    // impossible.    //    // This should never be implemented by hand.    #[doc(hidden)]    #[inline]    #[stable(feature = "rust1", since = "1.0.0")]    fn assert_receiver_is_total_eq(&self) {}}
复制代码


实现 Eq 的前提是已经实现了 PartialEq,因为实现 Eq 不需要额外的代码,只需要在实现了 PartialEq 的基础上告诉编译器它的比较满足自反性就可以了。对于上面的例子只需要:#[derive(Eq)]或 impl Eq for Book {}。


enum BookFormat {    Paperback,    Hardback,    Ebook,}
struct Book { isbn: i32, format: BookFormat,}
impl PartialEq for Book { fn eq(&self, other: &Self) -> bool { self.isbn == other.isbn }}
impl Eq for Book {}
复制代码

PartialEq 和 Eq


这两个 Traits 的名称实际上来自于抽象代数中的等价关系和局部等价关系。


等价关系(equivalence relation)即设 \displaystyle RR 是某个集合 \displaystyle AA 上的一个二元关系。若 \displaystyle RR 满足以下条件:

1.     自反性:\displaystyle \forall x\inA,~~xRx∀xA,  xRx

2.     对称性:\displaystyle \forall x,y\inA,~~xRy~~\implies ~~yRx∀x,yA,  xRy  ⟹  yRx

3.     传递性:\displaystyle \forall x,y,z\inA,~~~(xRy~~\wedge ~~yRz)~~\implies ~~xRz∀x,y,zA,   (xRy  ∧  yRz)  ⟹  xRz

则称 \displaystyle RR 是一个定义在 \displaystyle AA 上的等价关系


并非所有的二元关系都是等价关系, Eq 和 PartialEq 的区别在于是否在相等比较中是否满足自反性,即 x== x。


例如对于浮点类型,Rust 只实现了 PartialEq 而没有实现 Eq,原因在于 NaN!= Nan,不满足自反性。


Eq 相比 PartialEq 需要额外满足反身性,即 a== a,对于浮点类型,Rust 只实现了 PartialEq 而不是 Eq,原因就是 NaN!= NaN。

Eq 和 Hash


当一个类型同时实现了 Eq 和 Hash 时,该类型满足下列特性:


k1 == k2 -> hash(k1) == hash(k2)
复制代码


即,当两个 key 相等时,它们的哈希值必然相等。Rust 里的 HashMap 和 HashSet 都依赖该特性。


点击关注,第一时间了解华为云新鲜技术~


发布于: 2021 年 03 月 23 日阅读数: 8
用户头像

提供全面深入的云计算技术干货 2020.07.14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
实践解析丨Rust 内置 trait:PartialEq 和 Eq