前言
由于需要考虑全序关系(例如 Rust 浮点数中的 NaN),Rust 中有两套 trait 分别定义满足“全序”关系的 Ord/Eq 只能构成“偏序”关系的 PartialOrd/PartialEq。本文致力于用最短的篇幅覆盖标准库中Ord,Eq,PartialOrd,PartialEq
的主要知识点。
Eq/PartialEq
Eq 和 PartialEq 在概念上的区别主要是否满足 a == a
,乍看之下是句废话。实则不然,例如 a = NaN
就是特例。而在 trait 的定义上 Eq 是基于 PartialEq 的,Eq 自己更多是起修饰作用,在#[derive]
中,PartialEq 在类型字段全部相等时为 true反之false,而 Eq 只是约束类型全字段也满足 Eq。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
extern crate hello_rust;
#[derive(Debug, Eq)]
struct MyItem {
id: i32,
//... other Eq fields
}
impl PartialEq for MyItem {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
fn main() {
let item1 = MyItem { id: 1 };
let item2 = MyItem { id: 1 };
assert_eq!(item1, item2);
}
|
不难看出如果我们想用这套 trait,PartialEq 需要无脑怼上。需不需要 Eq 可以再考虑。
Ord/PartialOrd
和前文一样,做这种区分就是因为一些特殊值例如 NaN < 0 == false
并且 NaN >= 0 == false
。而在 trait 定义上 PartialOrd 基于 PartialEq 而 Ord 是 Eq + PartialOrd。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
use std::cmp::Ordering;
#[derive(Eq)]
struct Person {
id: u32,
name: String,
height: u32,
}
impl PartialOrd for Person {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Person {
fn cmp(&self, other: &Self) -> Ordering {
self.height.cmp(&other.height)
}
}
impl PartialEq for Person {
fn eq(&self, other: &Self) -> bool {
self.height == other.height
}
}
|
总结
虽然上例演示使用了这套 trait,不过还是要说除 ==
和 !=
以外的其他运算符的语义都比较固定,适用范围有限,避免滥用。