Rust语言从入门到精通系列 - 如何判断对象是否相等?

4 分钟阅读

在 Rust 语言中,PartialEq 和 Eq 是两个非常重要的 trait。它们用于比较类型的值,PartialEq 用于比较部分相等(不需要完全相等),而 Eq 用于比较完全相等。

在 Rust 中,任何类型都可以实现 PartialEq 和 Eq,因此这两个 trait 非常灵活。

基础用法

比较整数

1
2
3
4
5
6
7
8
9
fn main() {
    let a = 10;
    let b = 20;
    if a == b {
        println!("a equals b");
    } else {
        println!("a does not equal b");
    }
}

输出:

a does not equal b

比较字符串

1
2
3
4
5
6
7
8
9
fn main() {
    let a = "hello";
    let b = "world";
    if a == b {
        println!("a equals b");
    } else {
        println!("a does not equal b");
    }
}

输出:

a does not equal b

比较自定义类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#[derive(PartialEq, Eq)]
struct Person {
    name: String,
    age: u8,
}

fn main() {
    let p1 = Person {
        name: "Alice".to_string(),
        age: 30,
    };
    let p2 = Person {
        name: "Bob".to_string(),
        age: 30,
    };
    if p1 == p2 {
        println!("p1 equals p2");
    } else {
        println!("p1 does not equal p2");
    }
}

输出:

p1 does not equal p2

比较浮点数

1
2
3
4
5
6
7
8
9
fn main() {
    let a = 0.1 + 0.2;
    let b = 0.3;
    if a == b {
        println!("a equals b");
    } else {
        println!("a does not equal b");
    }
}

输出:

a does not equal b

自定义比较函数

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
27
28
29
#[derive(PartialEq, Eq)]
struct Person {
    name: String,
    age: u8,
}

impl PartialEq for Person {
    fn eq(&self, other: &Self) -> bool {
        self.age == other.age
    }
}

impl Eq for Person {}

fn main() {
    let p1 = Person {
        name: "Alice".to_string(),
        age: 30,
    };
    let p2 = Person {
        name: "Bob".to_string(),
        age: 30,
    };
    if p1 == p2 {
        println!("p1 equals p2");
    } else {
        println!("p1 does not equal p2");
    }
}

输出:

p1 equals p2

比较枚举类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#[derive(PartialEq, Eq)]
enum Color {
    Red,
    Blue,
}

fn main() {
    let c1 = Color::Red;
    let c2 = Color::Blue;
    if c1 == c2 {
        println!("c1 equals c2");
    } else {
        println!("c1 does not equal c2");
    }
}

输出:

c1 does not equal c2

使用 assert_eq!宏

1
2
3
4
5
fn main() {
    let a = 10;
    let b = 20;
    assert_eq!(a, b);
}

输出:

thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `10`,
 right: `20`', src/main.rs:4:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

使用 assert_ne!宏

1
2
3
4
5
fn main() {
    let a = 10;
    let b = 20;
    assert_ne!(a, b);
}

输出:

thread 'main' panicked at 'assertion failed: `(left != right)`
  left: `10`,
 right: `10`', src/main.rs:4:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

进阶用法

自定义比较函数

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
27
28
29
#[derive(PartialEq, Eq)]
struct Person {
    name: String,
    age: u8,
}

impl PartialEq for Person {
    fn eq(&self, other: &Self) -> bool {
        self.age == other.age
    }
}

impl Eq for Person {}

fn main() {
    let p1 = Person {
        name: "Alice".to_string(),
        age: 30,
    };
    let p2 = Person {
        name: "Bob".to_string(),
        age: 40,
    };
    if p1 == p2 {
        println!("p1 equals p2");
    } else {
        println!("p1 does not equal p2");
    }
}

输出:

p1 does not equal p2

使用泛型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#[derive(PartialEq, Eq)]
struct Pair<T> {
    first: T,
    second: T,
}

fn main() {
    let p1 = Pair {
        first: 1,
        second: 2,
    };
    let p2 = Pair {
        first: 2,
        second: 1,
    };
    if p1 == p2 {
        println!("p1 equals p2");
    } else {
        println!("p1 does not equal p2");
    }
}

输出:

p1 does not equal p2

使用 PartialOrd 和 Ord

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#[derive(PartialEq, Eq, PartialOrd, Ord)]
struct Person {
    name: String,
    age: u8,
}

fn main() {
    let p1 = Person {
        name: "Alice".to_string(),
        age: 30,
    };
    let p2 = Person {
        name: "Bob".to_string(),
        age: 40,
    };
    if p1 < p2 {
        println!("p1 is younger than p2");
    } else {
        println!("p1 is older than or equal to p2");
    }
}

输出:

p1 is younger than p2

使用 Debug 和 Display

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
#[derive(Debug, PartialEq, Eq)]
struct Person {
    name: String,
    age: u8,
}

use std::fmt;

impl fmt::Display for Person {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} ({})", self.name, self.age)
    }
}

fn main() {
    let p1 = Person {
        name: "Alice".to_string(),
        age: 30,
    };
    let p2 = Person {
        name: "Bob".to_string(),
        age: 40,
    };
    println!("p1: {}", p1);
    println!("p2: {}", p2);
}

输出:

p1: Alice (30)
p2: Bob (40)

最佳实践

在实现 PartialEq 和 Eq 时,应该考虑以下几点:

  • 对于自定义类型,应该比较所有的成员变量,而不仅仅是一部分。
  • 对于浮点数,应该使用近似比较而不是精确比较。
  • 对于枚举类型,应该比较所有的成员变量,而不仅仅是枚举值本身。
  • 如果需要比较的类型实现了 PartialOrd 和 Ord,应该优先使用这两个 trait。

结论

在 Rust 语言中,PartialEq 和 Eq 是非常重要的 trait,用于比较类型的值。这两个 trait 非常灵活,任何类型都可以实现它们。在实现 PartialEq 和 Eq 时,应该考虑到类型的特点,比较所有的成员变量,使用近似比较等。

知识共享许可协议

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 TinyZ Zzh (包含链接: https://tinyzzh.github.io ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。 如有任何疑问,请 与我联系 (tinyzzh815@gmail.com)

TinyZ Zzh

TinyZ Zzh

专注于高并发服务器、网络游戏相关(Java、PHP、Unity3D、Unreal Engine等)技术,热爱游戏事业, 正在努力实现自我价值当中。

评论

  点击开始评论...