Nugget 4
Home
You write if a == b and the compiler says no. Here's how to make
equality work on your types using PartialEq.
struct Point { x: i32, y: i32 }
fn main() {
let a = Point { x: 1, y: 2 };
let b = Point { x: 1, y: 2 };
if a == b { // ❌ binary operation `==` cannot be applied
println!("same!");
}
}
Rust doesn't assume anything about equality. You have to tell it — and that's
what the PartialEq trait is for.
#[derive(PartialEq)]
Add #[derive(PartialEq)] — Rust generates field-by-field
comparison automatically:
#[derive(PartialEq)]
struct Point { x: i32, y: i32 }
fn main() {
let a = Point { x: 1, y: 2 };
let b = Point { x: 1, y: 2 };
let c = Point { x: 5, y: 5 };
println!("a == b: {}", a == b); // ✅ true
println!("a != c: {}", a != c); // ✅ true
}
💡 You get != for free
Implement PartialEq and both == and !=
start working automatically — the trait provides the negation for you.
PartialEq works recursively — every field must also implement it:
#[derive(PartialEq)]
struct Point { x: i32, y: i32 }
#[derive(PartialEq)]
struct Line { start: Point, end: Point }
fn main() {
let a = Line {
start: Point { x: 0, y: 0 },
end: Point { x: 10, y: 10 },
};
let b = Line {
start: Point { x: 0, y: 0 },
end: Point { x: 10, y: 10 },
};
println!("{}", a == b); // ✅ true — compares field by field by field
}
If Point didn't implement PartialEq, the derive on
Line would fail at compile time. Rust checks this for you.
If field-by-field comparison isn't what you want, implement PartialEq
by hand:
struct User {
id: u64,
name: String,
}
impl PartialEq for User {
fn eq(&self, other: &Self) -> bool {
self.id == other.id // two users are equal if same ID
} // even if names differ
}
fn main() {
let a = User { id: 1, name: "Alice".into() };
let b = User { id: 1, name: "Alyssa".into() };
println!("{}", a == b); // ✅ true — same id
}
Eq vs PartialEq
You'll often see #[derive(PartialEq, Eq)]. What's the difference?
trait PartialEq<Rhs: ?Sized = Self> {
fn eq(&self, other: &Rhs) -> bool;
fn ne(&self, other: &Rhs) -> bool { !self.eq(other) }
}
trait Eq: PartialEq<Self> {} // just a marker — no methods
Eq is a marker trait that says "this type has total equality" —
every value is equal to itself (reflexive). Most types qualify, but floats
(f32, f64) don't — because NaN != NaN.
// f64 implements PartialEq (NaN != NaN breaks reflexivity)
// but does NOT implement Eq
let nan = f64::NAN;
println!("{}", nan == nan); // ❌ false — NaN is never equal to itself
// Your struct: derive PartialEq + Eq when every field is Eq
#[derive(PartialEq, Eq)]
struct Point { x: i32, y: i32 } // i32 implements Eq
💡 When to add Eq?
Add Eq whenever PartialEq makes sense and your
type doesn't contain floats. It enables types like HashMap and
HashSet, which require Eq. When in doubt,
#[derive(PartialEq, Eq)] is the standard practice.
#[derive(PartialEq)] makes == and != work on your types.PartialEq.PartialEq by hand when you need custom logic (e.g. compare by ID only).Eq is a marker trait for "total equality" — add it when PartialEq isn't enough (e.g. for HashMap keys).f32, f64) implement PartialEq but not Eq — NaN != NaN.