The Error ScenarioYou've just defined a new struct to hold your data, but as soon as you try to compare two instances, the compiler throws a fit. This usually happens when using the equality (==) or inequality (!=) operators on custom types.
Take a look at this snippet:
struct User {
id: u32,
username: String,
}
fn main() {
let user1 = User { id: 1, username: String::from("alice") };
let user2 = User { id: 1, username: String::from("alice") };
if user1 == user2 { // The compiler stops here
println!("Users are the same");
}
}
Running cargo build triggers a familiar wall of red text:
error[E0369]: binary operation `==` cannot be applied to type `User`
--> src/main.rs:10:14
|
10 | if user1 == user2
| ----- ^^ ---- User
| |
| User
|
note: an implementation of `PartialEq` might be missing for `User`
Why This HappensComing from Python or JavaScript? You might expect the runtime to compare objects automatically. Rust, however, refuses to guess. It prioritizes explicitness and performance, so it won't assume how you want to compare complex data structures.
To use the == operator, your type must implement the PartialEq trait. This trait provides the logic the compiler needs to check for equality. Without it, Rust has no instructions on whether to compare every field or just a specific ID.
The Quick Fix: Using #[derive]The fastest way to fix this is to let Rust write the code for you. If you want two instances to be equal only when every single field matches, use a procedural macro.
Simply add #[derive(PartialEq)] above your struct definition:
#[derive(PartialEq)]
struct User {
id: u32,
username: String,
}
fn main() {
let user1 = User { id: 1, username: String::from("alice") };
let user2 = User { id: 1, username: String::from("alice") };
assert_eq!(user1, user2); // This now works perfectly
}
Important RequirementFor the macro to work, every field inside your struct must also implement PartialEq. Standard types like u32, f32, and String already do this. However, if your struct contains a custom Address struct that lacks this trait, the compiler will point to that specific field as the culprit.
The Precise Fix: Manual ImplementationStandard field-by-field comparison isn't always the right move. Imagine an InventoryItem where only a unique sku matters for equality, even if the timestamp or quantity differs. In these cases, you should implement the trait manually.
struct InventoryItem {
sku: u32,
quantity: i32,
}
impl PartialEq for InventoryItem {
fn eq(&self, other: &Self) -> bool {
self.sku == other.sku
}
}
fn main() {
let item1 = InventoryItem { sku: 1001, quantity: 5 };
let item2 = InventoryItem { sku: 1001, quantity: 500 };
// This returns true because we only care about the SKU
if item1 == item2 {
println!("Same product, different stock levels");
}
}
PartialEq vs. Eq: What's the Difference?You'll likely see the Eq trait mentioned alongside PartialEq. While they look similar, they serve different mathematical purposes:
- PartialEq: Handles comparisons where a value might not equal itself. For example, in IEEE 754 floating-point math,
NaN == NaNis false.- Eq: This is a marker trait for "total equality." It tells the compiler that for every valuea,a == amust always be true.If your struct doesn't use floating-point numbers (f32orf64), it's best practice to derive both. This allows you to use your type as a key in aHashMap, which requires total equality.
#[derive(PartialEq, Eq)]
struct Product {
id: u64,
}
Verifying the FixOnce you've added the trait, verify it with two quick checks. First, run cargo check to ensure the E0369 error has vanished. Second, write a unit test to confirm your logic works as intended.
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_equality() {
let p1 = Product { id: 500 };
let p2 = Product { id: 500 };
assert!(p1 == p2);
}
}
Run cargo test. If you see the green "ok" message, your custom type is now fully compatible with Rust's comparison operators.

