摘要:Rust 在不少地方使用了 traits, 从很是浅显的操做符重载, 到 Send, Sync 这种很是微妙的特性。
本文分享自华为云社区《Rust 内置 trait 解析:PartialEq 和 Eq》,原文做者:debugzhang函数
Rust 在不少地方使用了 traits, 从很是浅显的操做符重载, 到 Send, Sync 这种很是微妙的特性。一些 traits 是能够被自动派生的(你只须要写#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Hash, ...)] 就能获得一个神奇的实现, 它一般是对的。flex
PartialEq 和 Eq这两个 Traits 的名称实际上来自于抽象代数中的等价关系和局部等价关系,实际上二者的区别仅有一点,便是否在相等比较中是否知足反身性(Reflexivity)。ui
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。this
PartialEq 可以使用 #[derive] 来交由编译器实现,当一个 struct 在进行相等比较时,会对其中每个字段进行比较;若是遇到枚举时,还会对枚举所拥有的数据进行比较。url
咱们也能够本身实现 PartialEq,实现时只须要实现判断是否相等的函数 fn eq(&self, other: &Self) -> bool ,Rust 会自动提供 fn ne(&self, other: &Self) -> bool。例子以下:spa
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 {}。.net
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 的名称实际上来自于抽象代数中的等价关系和局部等价关系。debug
等价关系(equivalence relation)即设 \displaystyle RR 是某个集合 \displaystyle AA 上的一个二元关系。若 \displaystyle RR 知足如下条件:code
则称 \displaystyle RR 是一个定义在 \displaystyle AA 上的等价关系。component
并不是全部的二元关系都是等价关系, 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 都依赖该特性。