rust语言学习笔记Trait(九)PartialEq、 Eq(相等比较)

1. 核心定义与区别

PartialEq:部分等价关系

  • ‌定义‌:允许某些值不与自身相等。
  • ‌核心方法 ‌:fn eq(&self, other: &Rhs) -> bool 和 fn ne(&self, other: &Rhs) -> bool。
  • ‌典型场景 ‌:浮点数 (f32, f64)。因为 NaN != NaN,所以浮点数只能实现 PartialEq,不能实现 Eq。 f64::NAN != f64::NAN
  • ‌数学性质 ‌:满足对称性(若 ab 则 ba)和传递性(若 ab 且 bc 则 ac),但‌不要求自反性‌(aa 不一定成立)。

Eq:完全等价关系

  • ‌定义 ‌:标记 Trait(Marker Trait),没有方法。它依赖于 PartialEq,并承诺满足自反性。
  • ‌核心约束 ‌:对于所有 a,a == a 必须返回 true。
  • ‌典型场景 ‌:整数、字符串、布尔值、结构体(如果其所有字段都实现了 Eq)。
  • ‌作用 ‌:作为类型系统的约束,确保该类型可以用于需要严格相等性的场景(如 HashMap 的键、BTreeSet 等)。

HashMap 的键必须实现 Eq 以及 Hash,在编译期就阻止了使用 f32/f64 作为键,从而避免了这类运行时 bug。

2、自定义结构体派生PartialEq、 Eq

rust 复制代码
use std::collections::HashMap;

// 子类型有浮点类型不能派生 Eq
// 因为 f32 没有实现 Eq
#[derive(Debug, PartialEq)]          
struct Point {
    x: f32,
    y: f32,
}

#[derive(Debug, PartialEq, Eq, Hash)] 
struct User {
    name: String,                 // String 实现了 Eq
    age: i32,                     // i32 实现了 Eq
}

fn main() {
    let p1 = Point { x: 1.2, y: 5.6 };
    let p2 = Point { x: 1.2, y: 5.6 };
    println!("{}", p1 == p2);             // true

    let u1 = User { name: String::from("Jane"), age: 18 };
    let u2 = User { name: String::from("Jane"), age: 18 };
    println!("{}", u1 == u2);            // true

    let mut hm = HashMap::new();
    hm.insert(u1, "Jjjj");              // 实现了PartialEq, Eq, Hash,可以做键
    println!("{:?}", hm.get(&u2));      // Some("Jjjj")
}

3、自定义类型手动实现PartialEq、Eq

rust 复制代码
// 自定义类型
struct MyStr(String);

// 实现 PartialEq
impl PartialEq for MyStr {
    // 实现 eq 方法
    fn eq(&self, other: &Self) -> bool {
        self.0.to_lowercase() == other.0.to_lowercase()      // 转换为小写
    }
}

// 实现 Eq
// Eq 是一个标记 Trait,没有任何方法
// 只需写下面这句代码
impl Eq for MyStr {}

fn main() {
    let ms1 = MyStr(String::from("Hello"));
    let ms2 = MyStr(String::from("heLLo"));
    println!("{}", ms1 == ms2);               // true,忽略大小写进行比较
}

ne 方法(不等于)

  • 通常不需要手动实现 ne(不等于)。PartialEq trait 提供了默认的 ne 实现:
rust 复制代码
fn ne(&self, other: &Rhs) -> bool {
    !self.eq(other)
}

除非你有性能优化的特殊需求(例如可以直接判断不相等而无需完整比较),否则省略它即可。

4、自定义结构体手动实现PartialEq、Eq,只比较部分属性

rust 复制代码
// 自定义类型
struct MyStruct {
    name: String,
    age: u8,
    time: u64,
}

// 实现 PartialEq
impl PartialEq for MyStruct {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name && self.age == other.age   // 不比较time
    }
}
// 实现 Eq
impl Eq for MyStruct {}

fn main() {
    let ms1 = MyStruct { name: String::from("小刚"), age: 18, time: 33 };
    let ms2 = MyStruct { name: String::from("小刚"), age: 18, time: 65 };
    println!("{}", ms1 == ms2);      // true
}
相关推荐
La Pulga1 小时前
【FreeRTOS源码学习笔记】空闲任务与阻塞延时
笔记·mcu·学习·嵌入式·freertos·实时操作系统
蒸蒸yyyyzwd1 小时前
秋招学习笔记 day106
笔记·学习
小李不想当小白3 小时前
WDG看门狗(STM32标准库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·嵌入式
欢欢李3 小时前
【LTE L3 笔记 04】LTE帧结构
笔记·无线通信·物理层·lte·空口协议
Zhao-Jichao5 小时前
AI Prompting for Everyone 课程笔记 - P20 实验与期末项目 Lab and Final Project
前端·人工智能·笔记
lisw056 小时前
作为人类代理的大语言模型及其角色分类!
人工智能·学习·语言模型
Z21-X6 小时前
云原生运维实战笔记:企业网站综合上云部署与云运维服务全景解析
运维·笔记·学习·云原生
坤坤子吖6 小时前
Linux网络编程:UDP进阶,从字典服务器到简单聊天室
linux·服务器·网络·c++·笔记·学习
Rabitebla6 小时前
【Linux学习笔记】进程篇(九):进程的创建与退出——fork、写时拷贝与退出码
linux·c++·笔记·学习
楚山之石7 小时前
【MRM】CAPLEX 对比剂灌注 MRI 开源术语库:ISMRM OSIPI 共识报告
图像处理·人工智能·学习·mri