1. 程式人生 > >Rust 內建 trait :PartialEq 和 Eq

Rust 內建 trait :PartialEq 和 Eq

> GitHub: https://github.com/storagezhang > > Emai: [email protected] > > 華為雲社群: https://bbs.huaweicloud.com/blogs/250275 > [Eq](https://doc.rust-lang.org/std/cmp/trait.Eq.html) and [PartialEq](https://doc.rust-lang.org/std/cmp/trait.PartialEq.html) are traits that allow you to define total and partial equality between values, respectively. Implementing them overloads the == and != operators. # PartialEq ```rust /// [`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 { /// 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`。例子如下: ```rust 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 ```rust pub trait Eq: PartialEq { // 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 {}`。 ```rust 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$ 滿足以下條件: 1. 自反性:$\displaystyle \forall x\in A,~~xRx$ 2. 對稱性:$\displaystyle \forall x,y\in A,~~xRy~~\implies ~~yRx$ 3. 傳遞性:$\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` 時,該型別滿足下列特性: ```text k1 == k2 -> hash(k1) == hash(k2) ``` 即,當兩個 key 相等時,它們的雜湊值必然相等。Rust 裡的 `HashMap` 和 `HashSet` 都依賴該