rust语言学习笔记Trait(十)PartialOrd、Ord(大小比较)

在 Rust 中,PartialOrdOrd 是定义类型排序能力的两个核心 trait。简单说:‌**PartialOrd 表示"部分排序",Ord 表示"全序"**‌。所有需要比较大小、排序的数据结构都离不开它们。

继承关系:

rust 复制代码
PartialEq → Eq
PartialEq → PartialOrd            // PartialOrd 必须实现 PartialEq
PartialEq、 Eq 、PartialOrd → Ord  // Ord 必须实现 PartialEq、 Eq 、PartialOrd

1、x.partial_cmp(&y) 方法,大小比较

x.partial_cmp(&y) 的返回类型是 Option<Ordering>,所以一共有 ‌4 种可能的结果‌:

结果 含义
Some(Ordering::Less) x 小于 y
Some(Ordering::Equal) x 等于 y
Some(Ordering::Greater) x 大于 y
None xy无法比较 ‌(例如涉及 NaN
rust 复制代码
fn main() {
    let x = 50;
    let y = 60;
    println!("{:?}", x.partial_cmp(&y));    // Some(Less)
}

1、PartialOrd------部分排序

  • PartialOrd ‌**要求类型必须先实现 PartialEq**‌,因为排序的前提是能判断相等。

  • 部分排序允许两个值之间‌可能无法比较 ‌。最典型的例子就是浮点数中的 NaNNaN 与任何值(包括它自己)比较都是无意义的,因此浮点数只能实现 PartialOrd

  • PartialOrd trait 的核心方法是 partial_cmp

rust 复制代码
fn partial_cmp(&self, other: &Self) -> Option<Ordering>;
  • 它返回 Option<Ordering>,当值无法排序时返回 None
rust 复制代码
fn main() {
    let x = 1.0f64;
    let y = f64::NAN;
    println!("{:?}", x.partial_cmp(&y));    // None
}
  • PartialOrd 还提供了 <><=>= 这些比较运算符的默认实现,内部都依赖 partial_cmp

(1)x.partial_cmp(&y) 方法,大小比较

x.partial_cmp(&y) 的返回类型是 Option<Ordering>,所以一共有 ‌4 种可能的结果‌:

结果 含义
Some(Ordering::Less) x 小于 y
Some(Ordering::Equal) x 等于 y
Some(Ordering::Greater) x 大于 y
None xy无法比较 ‌(例如涉及 NaN
rust 复制代码
fn main() {
    let x = 50;
    let y = 60;
    println!("{:?}", x.partial_cmp(&y));    // Some(Less)
}

(2)自动派生PartialOrd

当在结构体或枚举上 #[derive(PartialEq, PartialOrd)] 时:

  • 结构体‌:按照字段从上到下的声明顺序,依次比较每个字段,第一个不等字段的结果即为整体结果。

    rust 复制代码
    #[derive(PartialEq, PartialOrd)]
    struct MyStruct {
        a: i32,
        b: i32,
    }
    
    fn main() {
        let m1 = MyStruct { a: 20, b: 55 };
        let m2 = MyStruct { a: 20, b: 10 };
        println!("{:?}", m1.partial_cmp(&m2));    // Some(Greater)
    }
  • 枚举‌:按照变体从上到下的声明顺序,靠前的变体小于靠后的变体;同一变体内的字段再按顺序比较。

    rust 复制代码
    #[derive(PartialEq, PartialOrd)]
    enum MyEnum {
        BBB,
        AAA,
        CCC,
    }
    
    fn main() {
        let m1 = MyEnum::BBB;
        let m2 = MyEnum::AAA;
        let m3 = MyEnum::CCC;
        println!("{:?}", m1.partial_cmp(&m2));    // Some(Less)
        println!("{:?}", m2.partial_cmp(&m3));    // Some(Less)
    }

2、Ord------全部排序

全序要求任意两个值‌都可以且必须能排出确定的大小‌,满足三个性质:

  • 完全性 ‌:对于任意 aba<ba==ba>b 三者有且只有一个成立。
  • 反对称性 ‌:若 a<b 则不可能 a>b
  • 传递性 ‌:若 a<bb<ca<c

Ord 的核心方法是 cmp,直接返回 Ordering(不再有 Option):

rust 复制代码
fn cmp(&self, other: &Self) -> Ordering;

因为任何两个值都能比较,所以 cmp 总是能返回 LessEqualGreater

Ord 还提供了实用的 maxmin 方法,可以直接找出两个值中的较大者或较小者。

(1)x.cmp(&y) 方法,大小比较

x.cmp(&y) 的返回类型是 Ordering,所以一共有 ‌4 种可能的结果**‌:

结果 含义
Ordering::Less x 小于 y
Ordering::Equal x 等于 y
Ordering::Greater x 大于 y
rust 复制代码
fn main() {
    let x = 50;
    let y = 60;
    println!("{:?}", x.cmp(&y));    // Less
}

(2)自动派生Ord

当在结构体或枚举上 #[derive(PartialEq, PartialOrd, Eq, Ord)] 时:

  • 结构体‌:按照字段从上到下的声明顺序,依次比较每个字段,第一个不等字段的结果即为整体结果。

    rust 复制代码
    #[derive(PartialEq, PartialOrd, Eq, Ord)]
    struct MyStruct {
        a: i32,
        b: i32,
    }
    
    fn main() {
        let m1 = MyStruct { a: 20, b: 55 };
        let m2 = MyStruct { a: 20, b: 10 };
        println!("{:?}", m1.cmp(&m2));        // Greater
    }
  • 枚举‌:按照变体从上到下的声明顺序,靠前的变体小于靠后的变体;同一变体内的字段再按顺序比较。

    rust 复制代码
    #[derive(PartialEq, PartialOrd, Eq, Ord)]
    enum MyEnum {
        BBB,
        AAA,
        CCC,
    }
    
    fn main() {
        let m1 = MyEnum::BBB;
        let m2 = MyEnum::AAA;
        let m3 = MyEnum::CCC;
        println!("{:?}", m1.cmp(&m2));    // Less
        println!("{:?}", m2.cmp(&m3));    // Less
    }

3、手动实现 PartialOrdOrd,比较一个值

rust 复制代码
// PartialOrd 必须实现 PartialEq
// Ord 必须实现 PartialEq、 Eq、PartialOrd
#[derive(PartialEq, Eq)]        // 通过派生实现 PartialEq, Eq
struct MyStruct {
    name: String,
    age: i32,
}

// 手动实现 PartialOrd
impl PartialOrd for MyStruct {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.age.partial_cmp(other.age)    // 仅比较年龄
    }
}

// 手动实现 Ord
impl Ord for MyStruct {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.age.cmp(other.age)     // 仅比较年龄
        }
    }
}

fn main() {
    let m1 = MyStruct { name: "小李".to_string(), age: 55 };
    let m2 = MyStruct { name: "小刘".to_string(), age: 10 };
    let m3 = MyStruct { name: "小王".to_string(), age: 80 };

    println!("{:?}", m1.partial_cmp(&m2));        // Some(Greater)
    println!("{:?}", m1.partial_cmp(&m3));        // Some(Less)

    println!("{:?}", m1.cmp(&m2));                // Greater
    println!("{:?}", m1.cmp(&m3));                // Less

}

4、手动实现 Ord,比较多个值

rust 复制代码
// Ord 必须实现 PartialEq、 Eq、PartialOrd
#[derive(PartialEq, Eq, PartialOrd)]
struct MyStruct {
    a: i32,
    b: i32,
    c: i32,
}

// 手动实现 Ord
impl Ord for MyStruct {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.b.cmp(&other.b)               // 先比较 b
            .then(self.c.cmp(&other.c))    // 再比较 c
            .then(self.a.cmp(&other.a))    // 最后比较 a
    }
}

fn main() {
    let m1 = MyStruct { a: 10, b: 5, c: 8 };
    let m2 = MyStruct { a: 5, b: 8, c: 8 };
    let m3 = MyStruct { a: 15, b: 5, c: 4 };

    println!("{:?}", m1.partial_cmp(&m2));   // Some(Greater) 自动派生 abc顺序 m1.a > m2.a
    println!("{:?}", m1.partial_cmp(&m3));   // Some(Less)    自动派生 abc顺序 m1.a < m3.a

    println!("{:?}", m1.cmp(&m2));           // Less      m1.b < m2.b
    println!("{:?}", m1.cmp(&m3));           // Greater   m1.c > m3.c

}
相关推荐
小雨笙笙44 分钟前
机器学习:线性回归学习
学习·机器学习·线性回归
HugoStudio_SWAN1 小时前
洛谷 P1420 / P1179 / B4262 最长连号、数字统计与词频统计——统计的三种面孔
c++·学习·程序人生·算法
是隼人1 小时前
buuctf-pwn [HarekazeCTF2019]baby_rop2(64位ret2libc)题解(学习过程持续更新)
c语言·学习·安全·pwn入门·ctf入门
aprilaaaaa3 小时前
(TC397 学习笔记)二、ICU和TIM的时钟计算
笔记·学习·fpga开发
hongmai6668883 小时前
ESP32-WROVER-IE-N4R8:外接天线+8MB内存,专治信号焦虑
笔记·单片机·嵌入式硬件·microsoft·risc-v
Persistent的粽子!3 小时前
C++:类与对象(一)
开发语言·c++·经验分享·笔记
xian_wwq4 小时前
【学习笔记】-深度认知系列-第8讲主流AI模型横向评测——GPT、Claude、Gemini、盘古、文心、通义
人工智能·笔记·学习
大牧师4 小时前
TypeORM 学习教程
数据库·sql·学习·node.js·orm·nest.js·typeorm
晨欣5 小时前
NVIDIA GPU 架构演进学习笔记(GPT-5.6 Terra 生成)
笔记·学习·gpu·显卡·nvidia·英伟达
tedcloud1235 小时前
OpenLogi 怎么搭建?用 Rust 打造一个轻量的 Logitech 外设管理工具
linux·运维·服务器·开发语言·后端·rust·开源