Ord în Rust

Ordonare totală: orice două valori se pot compara. cmp() returnează Ordering; necesar pentru sort(), BTreeMap, max().

Sintaxă
#[derive(PartialEq, Eq, PartialOrd, Ord)]
struct Tip { ... }

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

Ce face Ord

Ord spune că oricare două valori se pot compara și că rezultatul este mereu clar: mai mic, egal sau mai mare. Metoda cmp returnează direct un Ordering (nu un Option). Îl cer Vec::sort, BTreeMap, BTreeSet, BinaryHeap, Iterator::max și min.

Pentru a-l deriva ai nevoie de toți patru: #[derive(PartialEq, Eq, PartialOrd, Ord)]. Ordinea este cea a câmpurilor, ca la PartialOrd. Când vrei alt criteriu (după notă descrescător, apoi după nume), implementezi manual cmp, iar partial_cmp doar îl apelează: Some(self.cmp(other)). Toate patru trebuie să spună același lucru.

Parametri

Parametru Descriere
cmp(&self, other) Singura metodă obligatorie. max, min și clamp vin automat.

Ce returnează

cmp returnează Ordering: Less, Equal sau Greater.

Exemple

Exemplul 1: cmp pe valori obișnuite

use std::cmp::Ordering;

fn main() {
    println!("{:?}", 3.cmp(&7));
    println!("{:?}", "Iași".cmp("Cluj"));
    println!("{:?}", 'a'.cmp(&'a'));
    match 18.cmp(&21) {
        Ordering::Less => println!("prea tânăr"),
        Ordering::Equal => println!("exact vârsta minimă"),
        Ordering::Greater => println!("acces permis"),
    }
}

Rezultat

Less
Greater
Equal
prea tânăr

Exemplul 2: Implementare manuală: notă descrescător, apoi nume

use std::cmp::Ordering;

#[derive(PartialEq, Eq)]
struct Elev {
    nume: String,
    nota: u8,
}

impl Ord for Elev {
    fn cmp(&self, other: &Self) -> Ordering {
        other.nota.cmp(&self.nota).then_with(|| self.nume.cmp(&other.nume))
    }
}

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

fn main() {
    let mut elevi = vec![
        Elev { nume: "Radu".into(), nota: 8 },
        Elev { nume: "Ioana".into(), nota: 10 },
        Elev { nume: "Ana".into(), nota: 10 },
        Elev { nume: "Mihai".into(), nota: 9 },
    ];
    elevi.sort();
    for (loc, e) in elevi.iter().enumerate() {
        println!("{}. {} – {}", loc + 1, e.nume, e.nota);
    }
}

Rezultat

1. Ana – 10
2. Ioana – 10
3. Mihai – 9
4. Radu – 8

Exemplul 3: derive(Ord) pe un enum și BTreeSet

use std::collections::BTreeSet;

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Prioritate {
    Scazuta,
    Normala,
    Urgenta,
}

fn main() {
    let set: BTreeSet<Prioritate> =
        [Prioritate::Urgenta, Prioritate::Scazuta, Prioritate::Normala].into_iter().collect();
    println!("{set:?}");
    println!("cea mai mare: {:?}", set.iter().max());
}

Rezultat

{Scazuta, Normala, Urgenta}
cea mai mare: Some(Urgenta)

Greșeli frecvente

  • Implementezi cmp manual, dar lași #[derive(PartialOrd)]: < și sort vor folosi criterii diferite. Implementează partial_cmp prin Some(self.cmp(other)).
  • Scrii a.cmp(b) în loc de a.cmp(&b): cmp primește o referință.

Comenzi înrudite

  • Ordering: Rezultatul unei comparații: Less, Equal sau Greater; are then, then_with și reverse pentru sortări pe mai multe criterii.
  • PartialOrd: Trait-ul din spatele operatorilor <, >, <=, >=; partial_cmp poate returna None (ex. NaN la f64).
  • Ord::max: Returnează cea mai mare (max) sau cea mai mică (min) dintre două valori ale unui tip Ord.
  • Ord::clamp: Limitează o valoare la intervalul [min, max]: sub min devine min, peste max devine max.
  • Eq: Trait marker care promite egalitate completă (a == a mereu); cerut de chei în HashMap/HashSet și de Ord.