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
都依賴該特性。