Essential Standard Traits

PartialOrd and Ord

The PartialOrd and Ord traits in std::cmp define relative ordering comparisons (<, <=, >, >=), distinguishing between partial orders where some values may be incomparable (PartialOrd) and total orders where every pair of values has a well-defined ordering (Ord).

Trait Definitions

pub enum Ordering {
    Less,
    Equal,
    Greater,
}

pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
    fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;

    // Default implementations: lt (<), le (<=), gt (>), ge (>=)
}

pub trait Ord: Eq + PartialOrd<Self> {
    fn cmp(&self, other: &Self) -> Ordering;

    // Default implementations: max, min, clamp
}

PartialOrd::partial_cmp returns Option<Ordering>, yielding None when two values cannot be ordered (such as f64::NAN compared with any number). Ord::cmp returns Ordering directly and is required by sorting algorithms (slice::sort) and ordered collections (BTreeMap, BTreeSet, BinaryHeap).

Deriving Lexicographical Ordering

Applying #[derive(PartialEq, Eq, PartialOrd, Ord)] compares struct fields in top-to-bottom declaration order (and enum variants in declaration order):

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Release {
    major: u32,
    minor: u32,
    patch: u32,
}

fn main() {
    let mut releases = vec![
        Release { major: 2, minor: 0, patch: 0 },
        Release { major: 1, minor: 9, patch: 4 },
        Release { major: 1, minor: 12, patch: 0 },
    ];

    releases.sort();
    for r in &releases {
        println!("{}.{}.{}", r.major, r.minor, r.patch);
    }
}
1.9.4
1.12.0
2.0.0

Implementing Ord and PartialOrd Manually

When implementing both Ord and PartialOrd manually, delegate partial_cmp directly to Some(self.cmp(other)) so that Ord, PartialOrd, and PartialEq can never disagree:

use std::cmp::Ordering;

#[derive(Debug, Eq)]
struct Job {
    id: u64,
    priority: u8,
}

impl PartialEq for Job {
    fn eq(&self, other: &Self) -> bool {
        self.priority == other.priority
    }
}

impl Ord for Job {
    fn cmp(&self, other: &Self) -> Ordering {
        self.priority.cmp(&other.priority)
    }
}

impl PartialOrd for Job {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

fn main() {
    let a = Job { id: 1, priority: 3 };
    let b = Job { id: 2, priority: 9 };

    println!("a < b: {}", a < b);
    println!("max priority: {:?}", a.max(b).priority);
}
a < b: true
max priority: 9

Total Ordering of Floats with f64::total_cmp

Because f32 and f64 only implement PartialOrd, calling .sort() on a Vec<f64> does not compile. Use .sort_by(f64::total_cmp) to sort floating-point slices with IEEE 754 total ordering.