In this lesson, you will learn how to implement custom sorting logic for multi-field structures using PartialOrd and Ord.
When you want to compare custom structs, Rust provides two primary traits: PartialOrd (for types that have a partial, non-total ordering) and Ord (for types where any two elements can be compared). While you can use #[derive(Ord)] for simple cases, manually implementing these traits gives you granular control over how your data is sorted.
Comparing Multiple Fields
Imagine you are building a leaderboard for a game. You want to sort players primarily by their score (highest first), and secondarily by level (highest first).
use std::cmp::Ordering;
struct Player {
score: u32,
level: u32,
}
impl Ord for Player {
fn cmp(&self, other: &Self) -> Ordering {
// 1. Compare score first
match other.score.cmp(&self.score) {
Ordering::Equal => {
// 2. If scores match, compare level
other.level.cmp(&self.level)
}
// Otherwise, return the score comparison result
res => res,
}
}
}
// PartialOrd must be consistent with Ord
impl PartialOrd for Player {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
Why two traits?
Rust requires PartialOrd for types that might not have a total ordering (like floating-point numbers, where NaN cannot be compared to other numbers). Ord requires a "total" ordering, meaning every single pair of instances must have a defined relationship (Less, Greater, or Equal).
By using the cmp method, we return an Ordering enum. Notice how in the example above, we use other.score.cmp(&self.score) instead of self.score.cmp(&other.score). Because we want a descending sort (higher scores first), we flip the comparison. This pattern of chaining match statements is the standard way to handle multi-field logic. Whenever you implement Ord, you must also implement PartialOrd and Eq to ensure your type behaves predictably with collection types like BTreeSet or BinaryHeap.
Key Takeaway: Implement Ord by chaining cmp calls across your fields, using match to fall back to secondary fields only when primary fields are equal.