Course contentsShow
← Rust
Lesson 573 of 1,9105. Type System and TraitsFree lesson

PartialOrd and Ord Ordering Traits

Implement complex sorting and comparison logic for multi-field custom structures.

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.