Rust 语言常见 Trait 简介 😓
前言
在 Rust 中,Trait 是一种定义行为的机制,类似于其他语言中的接口(Interface)。它可以用来描述特定的行为和能力,并且可以被任何类型实现。
简述
Clone
:用于创建类型的副本。实现 Clone trait 可以通过 clone() 方法复制一个值,而不是将它移动(move)到一个新的变量中。Copy
:用于标记类型可以被拷贝到新的变量而不是移动(move)。实现 Copy trait 的类型,当它们被赋值或传递给函数时,将会被自动复制到新的变量中。Debug
:用于格式化输出调试信息。实现 Debug trait 可以使用 {:?} 格式化字符串来打印类型的调试信息。Default
:用于定义类型的默认值。实现 Default trait 可以通过默认值来初始化类型的实例。(其会为类型添加一个 default 方法)Deref
和DerefMut
:定义了一种自动解引用的机制,用于将一个类型的引用转换成另一个类型的引用。通过实现这两个 trait,可以让一个类型在需要时被自动解引用成为特定类型。Drop
:用于在类型被销毁时执行清理操作。实现 Drop trait 可以在类型被销毁之前执行一些特定的操作,例如释放内存。(析构)Eq
和PartialEq
:用于比较类型的相等性。实现 Eq 和 PartialEq trait 可以比较类型的相等性,其中 Eq trait 要求类型必须满足完全相等,而 PartialEq trait 则可以定义类型相等的自定义规则。Hash
:用于计算类型的哈希值。实现 Hash trait 可以为类型计算一个哈希值,用于将类型存储在哈希表中或进行其他哈希相关操作。Into
和From
:用于类型转换。实现 Into 和 From trait 可以在类型之间进行自动类型转换,其中 Into trait 是从当前类型到目标类型的转换,From trait 是从目标类型到当前类型的转换。Iterator
:用于实现迭代器。实现 Iterator trait 可以让类型变成一个迭代器,从而可以使用 for 循环等语法糖来遍历它们的元素。Sized
:用于标记类型大小的信息,例如 usize 是有限大小的,但 str 不是。实现 Sized trait 可以在编译时检查类型的大小。Sync
和Send
:用于实现线程安全。实现 Sync 和 Send trait 可以将类型标记为线程安全的,其中 Sync trait 用于表示类型可以安全地在多个线程中共享,而 Send trait 用于表示类型可以安全地在多个线程之间移动。TryInto
和TryFrom
:用于可失败类型转换。实现 TryInto 和 TryFrom trait 可以在类型之间进行类型转换,但是这些转换可能会失败。TryInto trait 定义了从当前类型到目标类型的转换,而 TryFrom trait 则定义了从目标类型到到当前类型的转换。
番外
Deref & DerefMut
Deref
trait 定义了一个函数 deref(&self) -> &T
,该函数返回一个指向 self
中数据的引用。这意味着如果我们有一个类型 A
,它实现了 Deref
trait,并且我们有一个类型为 A
的变量 a
,则我们可以使用 *a
来访问 A
类型中包含的数据(并非必须是 A
类型中包含的数据,详见下文)。
具体来说,编译器会自动地调用 a.deref()
函数,获取一个指向数据的引用,并对该引用进行解引用。这表示,通过 *a
获取到的其实是 defer
函数返回的数据。
1struct MyType(i32);
2
3impl Deref for MyType {
4 type Target = i32;
5
6 fn deref(&self) -> &Self::Target {
7 &self.0
8 }
9}
10
11impl DerefMut for MyType {
12 fn deref_mut(&mut self) -> &mut Self::Target {
13 &mut self.0
14 }
15}
16
17fn main() {
18 let mut a = MyType(42);
19 *a += 10;
20 assert_eq!(*a, 52);
21}
在这个例子中,我们创建了一个 MyType
结构体,它包含了一个 i32
类型的整数。我们实现了 Deref
trait,将 MyInt
转换为一个 i32
引用,并在 main()
函数中使用 *a
来访问该引用中的数据。
类似地,DerefMut
trait 也是用于自动解引用的,与 Deref
不同的是,它会返回一个可变引用 &mut T
。
上文曾提到通过 *a
获取到的其实是 defer
函数返回的数据,下面👇给出一个比较奇怪的例子🙈。
1lazy_static::lazy_static! {
2 pub static ref TEST: i64 = 0;
3}
4
5struct MyType(i32);
6
7impl Deref for MyType {
8 type Target = i64;
9
10 fn deref(&self) -> &Self::Target {
11 &TEST
12 }
13}
14
15fn main() {
16 let a = MyType(42);
17 assert_eq!(*a, 0);
18}
终末
本文仅列举了一部分常见的 Trait,Rust 中还有许多其他 Trait,可以通过 Rust 标准库文档进行查看和了解。Trait 是 Rust 语言的核心特性,掌握 Trait 的使用和实现方式对于编写高质量的 Rust 代码至关重要。
偷偷拿 Send
特性举例吐槽一下,完全由实现了 Send
Trait 的类型组成的类型也会自动(隐式)实现 Send
Trait。类似的规则还有不少,真是值得“赞赏”的、令人“欢喜”的设计。