Essential Standard Traits

PartialEq and Eq

The PartialEq and Eq traits in std::cmp define equality comparisons (== and !=), distinguishing between partial equivalence relations (PartialEq) and full equivalence relations (Eq).

Trait Definitions

pub trait PartialEq<Rhs: ?Sized = Self> {
    fn eq(&self, other: &Rhs) -> bool;

    fn ne(&self, other: &Rhs) -> bool {
        !self.eq(other)
    }
}

pub trait Eq: PartialEq<Self> {}

PartialEq requires implementing eq (and provides ne automatically). Eq is a marker trait with no methods that promises the PartialEq implementation is also reflexive (a == a for every value a).

Equivalence Relation Properties

Property Mathematical Rule Required by PartialEq? Required by Eq?
Symmetry a == b implies b == a Yes Yes
Transitivity a == b and b == c implies a == c Yes Yes
Reflexivity a == a is always true No Yes

Why Floating-Point Types Implement PartialEq but Not Eq

IEEE 754 floating-point types (f32 and f64) include the special value NaN (Not a Number). By the IEEE 754 specification, NaN == NaN evaluates to false, violating reflexivity. Consequently, f32 and f64 implement PartialEq so == and != work, but they do not implement Eq (and cannot be used directly as keys in HashMap<K, V>):

fn main() {
    let x = f64::NAN;
    println!("NaN == NaN: {}", x == x);
    println!("NaN != NaN: {}", x != x);
}
NaN == NaN: false
NaN != NaN: true

Custom PartialEq and Eq Implementation

When derived equality (#[derive(PartialEq, Eq)]) is not appropriate—for example, when two values should compare equal by ID regardless of cached metadata—implement PartialEq and Eq manually:

#[derive(Debug)]
struct UserSession {
    session_id: u64,
    last_ping_ms: u64,
}

impl PartialEq for UserSession {
    fn eq(&self, other: &Self) -> bool {
        self.session_id == other.session_id
    }
}

impl Eq for UserSession {}

fn main() {
    let s1 = UserSession {
        session_id: 42,
        last_ping_ms: 100,
    };
    let s2 = UserSession {
        session_id: 42,
        last_ping_ms: 950,
    };

    assert_eq!(s1, s2);
    println!("s1 == s2: {}", s1 == s2);
}
s1 == s2: true

Cross-Type Equality with PartialEq<Rhs>

Because PartialEq<Rhs = Self> has a default type parameter Rhs, you can implement PartialEq<OtherType> to compare values of two different types with == (for example, String implements PartialEq<str> and PartialEq<&str> so my_string == "literal" compiles without allocating).