Rust 内置 trait :PartialEq 和 Eq
GitHub: https://github.com/storagezhang
Emai: debugzhang@163.com
Eq and PartialEq are traits that allow you to define total and partial equality between values, respectively. Implementing them overloads the == and != operators.
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 会自动提供 fn ne(&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 R\) 是某个集合 \(\displaystyle A\) 上的一个二元关系。若 \(\displaystyle R\) 满足以下条件:
- 自反性:\(\displaystyle \forall x\in A,~~xRx\)
- 对称性:\(\displaystyle \forall x,y\in A,~~xRy~~\implies ~~yRx\)
- 传递性:\(\displaystyle \forall x,y,z\in A,~~~(xRy~~\wedge ~~yRz)~~\implies ~~xRz\)
则称 \(\displaystyle R\) 是一个定义在 \(\displaystyle A\) 上的等价关系。
并非所有的二元关系都是等价关系, 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
都依赖该特性。