PartialOrd în Rust

Trait-ul din spatele operatorilor <, >, <=, >=; partial_cmp poate returna None (ex. NaN la f64).

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

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

Ce face PartialOrd

PartialOrd permite comparațiile <, >, <=, >=. Metoda de bază, partial_cmp, returnează Some(Ordering) sau None când valorile nu se pot compara. La f64, orice comparație cu NaN dă None, iar operatorii dau false.

#[derive(PartialOrd)] compară „lexicografic”: întâi primul câmp, la egalitate al doilea și așa mai departe, în ordinea în care sunt declarate. La enum-uri, variantele declarate mai sus sunt mai mici. Ordinea câmpurilor din structură contează deci.

Pentru că rezultatul poate lipsi, sort() nu merge pe Vec<f64>. Folosește sort_by(|a, b| a.partial_cmp(b).unwrap()) dacă știi că nu ai NaN, sau sort_by(|a, b| a.total_cmp(b)).

Parametri

Parametru Descriere
partial_cmp(&amp;self, other) Singura metodă obligatorie; operatorii lt, le, gt, ge vin automat.

Ce returnează

Option<Ordering>; operatorii returnează bool.

Exemple

Exemplul 1: Ordinea câmpurilor și a variantelor

#[derive(Debug, PartialEq, PartialOrd)]
enum Marime {
    Mic,
    Mediu,
    Mare,
}

#[derive(Debug, PartialEq, PartialOrd)]
struct Versiune {
    major: u32,
    minor: u32,
}

fn main() {
    println!("Mic < Mare: {}", Marime::Mic < Marime::Mare);
    println!("Mediu >= Mare: {}", Marime::Mediu >= Marime::Mare);

    let a = Versiune { major: 1, minor: 99 };
    let b = Versiune { major: 2, minor: 0 };
    println!("1.{} < 2.{}: {}", a.minor, b.minor, a < b);
    println!("{:?}", a.partial_cmp(&b));
    println!("major: {} și {}", a.major, b.major);
}

Rezultat

Mic < Mare: true
Mediu >= Mare: false
1.99 < 2.0: true
Some(Less)
major: 1 și 2

Exemplul 2: Numere zecimale și NaN

fn main() {
    println!("{:?}", 2.5_f64.partial_cmp(&1.0));
    let nan = f64::NAN;
    println!("{:?}", nan.partial_cmp(&1.0));
    println!("NaN < 1: {}, NaN > 1: {}", nan < 1.0, nan > 1.0);

    let mut medii = vec![9.25, 7.5, 10.0, 8.75];
    medii.sort_by(|a, b| b.partial_cmp(a).unwrap());   // descrescător
    println!("{medii:?}");
}

Rezultat

Some(Greater)
None
NaN < 1: false, NaN > 1: false
[10.0, 9.25, 8.75, 7.5]

Greșeli frecvente

  • Apelezi sort() pe Vec<f64>: the trait `Ord` is not implemented for `f64`.
  • Schimbi ordinea câmpurilor unei structuri cu derive(PartialOrd) și se schimbă, pe tăcute, și ordinea de sortare.

Comenzi înrudite

  • Ord: Ordonare totală: orice două valori se pot compara. cmp() returnează Ordering; necesar pentru sort(), BTreeMap, max().
  • Ordering: Rezultatul unei comparații: Less, Equal sau Greater; are then, then_with și reverse pentru sortări pe mai multe criterii.
  • PartialEq: Trait-ul din spatele operatorilor == și !=; derive compară toate câmpurile, implementarea manuală alege criteriul.