概述

trait继承关系:

未命名文件.png
都可以通过#[derive()]的方式引入,使用其默认实现

对于浮点型来说,其值有可能是NaN

  • 使用PartialEq返回**false**)和PartialOrd返回**None**)时包含这种可能性
  • 但是Ord/Eq无法对其进行比较,在Ord/Eq的实现中:
    • Ord的实现是cmp方法

error[E0599]: the method cmp exists for type f64, but its trait bounds were
not satisfied
—> src\main.rs:22:20
|
22 | self.price.cmp(&other.price)
| ^^^ method cannot be called on f64 due to unsatisfied trait bounds

  • #[derive(Eq)]时,结构体中不能有浮点型字段:

error[E0277]: the trait bound f64: Eq is not satisfied
—> src\main.rs:7:5
|
7 | price:f64
| ^^^^^^^^^ the trait Eq is not implemented for f64

Ord trait用处

只有实现了Ord trait,才能使用sort方法、BTree

Eq trait用途

只有实现了Eq trait,才能将此对象用作Hashkey

PartialEq trait

定义

  1. pub trait PartialEq<Rhs = Self> where Rhs: ?Sized, {
  2. fn eq(&self, other: &Rhs) -> bool;
  3. // 实现eq方法后自动实现
  4. fn ne(&self, other: &Rhs) -> bool { ... }
  5. }

特点

符合

  • 对称性:a == b implies b == a
  • 传递性:a == b and b == c implies a == c

使用

用于定义结构体/枚举的比较方式

只用实现eq方法,ne方法自动实现

可以使用#[derive(PartialEq)]的方式引入,这样会使用默认实现:比较结构体的每个字段

When derived on structs, two instances are equal if all fields are equal, and not equal if any fields are not equal. When derived on enums, each variant is equal to itself and not equal to the other variants.

实现PartialEq trait后,Rust会默认提供一揽子泛型(generic blanket impls)实现,自动提供引用间的比较实现:

  1. // 不可变引用间比较
  2. impl<A, B> PartialEq<&'_ B> for &'_ A
  3. where A: PartialEq<B> + ?Sized, B: ?Sized;
  4. // 可变引用与不可变引用进行比较
  5. impl<A, B> PartialEq<&'_ B> for &'_ mut A
  6. where A: PartialEq<B> + ?Sized, B: ?Sized;
  7. // 不可变引用与可变引用进行比较
  8. impl<A, B> PartialEq<&'_ mut B> for &'_ A
  9. where A: PartialEq<B> + ?Sized, B: ?Sized;
  10. // 可变引用之间进行比较
  11. impl<A, B> PartialEq<&'_ mut B> for &'_ mut A
  12. where A: PartialEq<B> + ?Sized, B: ?Sized;

实例:为结构体实现比较方法:

  1. enum BookFormat {
  2. Paperback,
  3. Hardback,
  4. Ebook,
  5. }
  6. struct Book {
  7. isbn: i32,
  8. format: BookFormat,
  9. }
  10. impl PartialEq for Book {
  11. fn eq(&self, other: &Self) -> bool {
  12. // 指定比较的具体字段
  13. self.isbn == other.isbn
  14. }
  15. }
  16. let b1 = Book { isbn: 3, format: BookFormat::Paperback };
  17. let b2 = Book { isbn: 3, format: BookFormat::Ebook };
  18. let b3 = Book { isbn: 10, format: BookFormat::Paperback };
  19. assert!(b1 == b2);
  20. assert!(b1 != b3);

实例:比较不同类型

需要通过泛型指定要比较的目标
BookBookFormat之间的通过比较**format**字段的,所以需要为BookFormat加上#[derive(PartialEq)]

  1. // 为枚举引入PartialEq,实现枚举间的比较
  2. #[derive(PartialEq)]
  3. enum BookFormat {
  4. Paperback,
  5. Hardback,
  6. Ebook,
  7. }
  8. struct Book {
  9. isbn: i32,
  10. format: BookFormat,
  11. }
  12. // 实现为Book比较BookFormat
  13. impl PartialEq<BookFormat> for Book {
  14. fn eq(&self, other: &BookFormat) -> bool {
  15. self.format == *other
  16. }
  17. }
  18. // 实现为BookFormat比较Book
  19. impl PartialEq<Book> for BookFormat {
  20. fn eq(&self, other: &Book) -> bool {
  21. *self == other.format
  22. }
  23. }
  24. let b1 = Book { isbn: 3, format: BookFormat::Paperback };
  25. let b2 = Book { isbn: 2, format: BookFormat::Paperback };
  26. assert!(b1 == BookFormat::Paperback);
  27. assert!(BookFormat::Ebook != b1);
  28. // 实现Book间的比较
  29. // 通过自定义相同类型的比较,实现了传递性
  30. impl PartialEq for Book {
  31. fn eq(&self, other: &Self) -> bool {
  32. // 指定比较的具体字段
  33. self.format == other.format
  34. }
  35. }
  36. assert!(b1 == b2);

Eq

定义

pub trait Eq: PartialEq<Self> { }

Eq是标记trait,它标识相等性,且要求所有字段相等,它没有要实现的方法

特点

除了对称性传递性,还需要满足自反性:a == a

使用:

如果一个类型全部成员都实现了 Eq 特性,那么该类型本身也可以衍生出该特性

所有的浮点类型都实现了PartialEq但是没有实现 Eq ,因为 NaN != NaN

几乎所有其它实现 PartialEq 的类型也都自然地实现了 Eq ,除非它们包含了浮点数

需要实现**PartialEq trait**
需要使用Eq trait时,需要先实现这个类型的PartialEq trait,然后使用#[derive(Eq)]的方式,实现Eq trait

PartialOrd

定义

  1. enum Ordering {
  2. Less,
  3. Equal,
  4. Greater,
  5. }
  6. pub trait PartialOrd<Rhs = Self>: PartialEq<Rhs> where Rhs: ?Sized, {
  7. fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;
  8. // 提供默认实现
  9. fn lt(&self, other: &Rhs) -> bool { ... }
  10. fn le(&self, other: &Rhs) -> bool { ... }
  11. fn gt(&self, other: &Rhs) -> bool { ... }
  12. fn ge(&self, other: &Rhs) -> bool { ... }
  13. }

实现PartialOrd<Rhs>的类型可以和Rhs的类型之间使用<,<=,>,和 >=算符。

特点

对比较的内容,需要满足:

  • 不对称性: if a < b then !(a > b), as well as a > b implying !(a < b)
  • 传递性:a < b and b < c implies a < c

对于NaN,为其比较时,会返回None

  1. let result = f64::NAN.partial_cmp(&1.0);
  2. assert_eq!(result, None);

使用

可以使用#[derive(PartialOrd)]引入

This trait can be used with #[derive]. When derived on structs, it will produce a lexicographic ordering based on the top-to-bottom declaration order of the struct’s members. When derived on enums, variants are ordered by their top-to-bottom discriminant order.

当在结构上引入时,它将根据结构成员的自上而下声明顺序生成字典顺序。在枚举上派生时,变体按其从上到下的判别顺序排序。

可用于指定Vector中类型实例的排序规则

自定义实现时,只需要实现partial_cmp方法

PartialOrd traitPartialEq trait的子trait,二者的实现需要保持一致
PartialOrd trait要求同时实现PartialEq trait

PartialOrd 改良了 PartialEq ,后者仅能比较是否相等,而前者除了能比较是否相等,还能比较孰大孰小。

如果特定类型的全部成员都实现了 PartialOrd 特性,那么该类型也可以衍生出该特性:

示例:使用浮点型来比较

  1. use std::cmp::Ordering;
  2. struct Person {
  3. id: u32,
  4. name: String,
  5. height: f64,
  6. }
  7. impl PartialOrd for Person {
  8. fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
  9. self.height.partial_cmp(&other.height)
  10. }
  11. }
  12. impl PartialEq for Person {
  13. fn eq(&self, other: &Self) -> bool {
  14. self.height == other.height
  15. }
  16. }

Ord

定义

  1. pub trait Ord: Eq + PartialOrd<Self> {
  2. fn cmp(&self, other: &Self) -> Ordering;
  3. // 提供默认实现
  4. fn max(self, other: Self) -> Self { ... }
  5. fn min(self, other: Self) -> Self { ... }
  6. fn clamp(self, min: Self, max: Self) -> Self { ... }
  7. }

特点

更加严格的顺序:对于任意 ab 仅有一个为真: a < ba == ba > b

NaNNaN < 0 == falseNaN >= 0 == false 同时为真,不满足上面三个任一一个条件,所以不满足Ord trait

使用

可以使用#[derive(Eq)]引入

This trait can be used with #[derive]. When derived on structs, it will produce a lexicographic ordering based on the top-to-bottom declaration order of the struct’s members. When derived on enums, variants are ordered by their top-to-bottom discriminant order.

当在结构上引入时,它将根据结构成员的自上而下声明顺序生成字典顺序。在枚举上派生时,变体按其从上到下的判别顺序排序。

Ord requires that the type also be PartialOrd and Eq (which requires PartialEq).

需同时实现PartialOrdEq

自定义实现时,只需要实现cmp方法

对于实现了Ord特性的类型,我们可以将它存储于BTreeMapBTreeSet,并且可以通过sort()方法对切片,或者任何可以自动解引用为切片的类型进行排序,例如VecVecDeque

示例:同时实现PartialOrdPartialEqOrd

  1. use std::cmp::Ordering;
  2. #[derive(Eq)]
  3. struct Person {
  4. id: u32,
  5. name: String,
  6. height: u32,
  7. }
  8. impl PartialEq for Person {
  9. fn eq(&self, other: &Self) -> bool {
  10. self.height == other.height
  11. }
  12. }
  13. impl PartialOrd for Person {
  14. fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
  15. // 最好是调用Ord的cmp方法进行比较
  16. Some(self.cmp(other))
  17. }
  18. }
  19. impl Ord for Person {
  20. fn cmp(&self, other: &Self) -> Ordering {
  21. self.height.cmp(&other.height)
  22. }
  23. }