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