Abstract:Rust uses traits in many ways, from the very superficial operator overloading to more subtle features like Send and Sync.

This article is from The Huawei Cloud community Rust Built-in Trait Analysis: PartialEq and Eq, by Debugzhang

Rust uses traits in many ways, from the very superficial operator overloading to more subtle features like Send and Sync. Some traits can be derived automatically (you just need to write #[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Hash,…))] You get an amazing implementation, which is usually true.

The names of PartialEq and Eq, two Traits, actually come from equivalence relation and local equivalence relation in abstract algebra. In fact, there is only one difference between them, namely whether Reflexivity is satisfied in equality comparison.

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)
    }
}

If we want to compare two values of a certain type, x and y, for example: x == y (x! = y), then we must implement the PartialEq Trait for the type.

PartialEq can be implemented by the compiler using #[derive], and when a struct is compared for equality, each of its fields is compared; If an enumeration is encountered, the data owned by the enumeration is also compared.

We can also implement PartialEq ourselves by implementing fn eq(&self, other: &self) -> bool. Rust will automatically provide fn ne(&self, other: &self) -> bool. Here’s an example:

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) {}}

The premise of implementing Eq is that PartialEq is already implemented, because implementing Eq requires no additional code, only that it tells the compiler that its comparison satisfies reflexivity based on implementing PartialEq. For the example above, all you need is: #[derive(Eq)] or 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 and Eq

The names of these two Traits actually come from the equivalence and local equivalence relationships in abstract algebra.

Equivalence relation is to set displaystyle R_R_ to be a binary relation on some set displaystyle A_A_. If displaystyle R_R_ satisfies the following conditions:

Displaystyle R_R_ is an equivalent relation defined on displaystyle A_A_.

Not all binary relations are equivalent relations, and the difference between Eq and PartialEq is whether reflexivity is satisfied in the equality comparison, i.e., x == x.

For floating point types, for example, Rust implements only PartialEq and not Eq because of NaN! = Nan, not reflexive.

Eq needs to satisfy additional reflexivity compared to PartialEq, i.e. a == a. For floating point types, Rust only implements PartialEq and not Eq, because of NaN! = NaN.

Eq and Hash

When a type implements both Eq and Hash, the type satisfies the following characteristics:

k1 == k2 -> hash(k1) == hash(k2)

That is, when two keys are equal, their hashes must be equal. Both HashMaps and Hashsets in Rust rely on this feature.

Click follow to learn about the fresh technologies of Huawei Cloud