🍉 加载中...


Rust 语言常见 Trait 简介 😓

7 minute read

前言

在 Rust 中,Trait 是一种定义行为的机制,类似于其他语言中的接口(Interface)。它可以用来描述特定的行为和能力,并且可以被任何类型实现。

简述

  • Clone:用于创建类型的副本。实现 Clone trait 可以通过 clone() 方法复制一个值,而不是将它移动(move)到一个新的变量中。
  • Copy:用于标记类型可以被拷贝到新的变量而不是移动(move)。实现 Copy trait 的类型,当它们被赋值或传递给函数时,将会被自动复制到新的变量中。
  • Debug:用于格式化输出调试信息。实现 Debug trait 可以使用 {:?} 格式化字符串来打印类型的调试信息。
  • Default:用于定义类型的默认值。实现 Default trait 可以通过默认值来初始化类型的实例。(其会为类型添加一个 default 方法)
  • DerefDerefMut:定义了一种自动解引用的机制,用于将一个类型的引用转换成另一个类型的引用。通过实现这两个 trait,可以让一个类型在需要时被自动解引用成为特定类型。
  • Drop:用于在类型被销毁时执行清理操作。实现 Drop trait 可以在类型被销毁之前执行一些特定的操作,例如释放内存。(析构)
  • EqPartialEq:用于比较类型的相等性。实现 Eq 和 PartialEq trait 可以比较类型的相等性,其中 Eq trait 要求类型必须满足完全相等,而 PartialEq trait 则可以定义类型相等的自定义规则。
  • Hash:用于计算类型的哈希值。实现 Hash trait 可以为类型计算一个哈希值,用于将类型存储在哈希表中或进行其他哈希相关操作。
  • IntoFrom:用于类型转换。实现 Into 和 From trait 可以在类型之间进行自动类型转换,其中 Into trait 是从当前类型到目标类型的转换,From trait 是从目标类型到当前类型的转换。
  • Iterator:用于实现迭代器。实现 Iterator trait 可以让类型变成一个迭代器,从而可以使用 for 循环等语法糖来遍历它们的元素。
  • Sized:用于标记类型大小的信息,例如 usize 是有限大小的,但 str 不是。实现 Sized trait 可以在编译时检查类型的大小。
  • SyncSend:用于实现线程安全。实现 Sync 和 Send trait 可以将类型标记为线程安全的,其中 Sync trait 用于表示类型可以安全地在多个线程中共享,而 Send trait 用于表示类型可以安全地在多个线程之间移动。
  • TryIntoTryFrom:用于可失败类型转换。实现 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。类似的规则还有不少,真是值得“赞赏”的、令人“欢喜”的设计。