實踐解析丨Rust 內置 trait:PartialEq 和 Eq

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

 

點擊關注,第一時間瞭解華爲雲新鮮技術~

相關文章
相關標籤/搜索