特殊类型和 trait

标准库中的某些类型和 trait 对 Rust 编译器是已知的。本章介绍了这些类型和 trait 的特殊特性。

Box<T>

Box<T> 具有一些特殊特性,这些特性目前 Rust 不允许用户自定义类型拥有。

  • Box<T>解引用运算符会产生一个可以从中移出 (moved from) 的位置 (place)。这意味着 * 运算符和 Box<T> 的析构器是语言内建的。
  • 方法可以将 Box<Self> 作为接收者 (receiver)。
  • trait 可以为 Box<T> 在与 T 相同的 crate 中实现,而孤儿规则 (orphan rules) 会阻止其为其他泛型类型实现。

Rc<T>

方法可以将 Rc<Self> 作为接收者。

Arc<T>

方法可以将 Arc<Self> 作为接收者。

Pin<P>

方法可以将 Pin<P> 作为接收者。

UnsafeCell<T>

std::cell::UnsafeCell<T> 用于实现内部可变性 (interior mutability)。它确保编译器不会对这类类型执行不正确的优化。

它还确保具有内部可变性的类型的 static不会被放置在标记为只读的内存中。

PhantomData<T>

std::marker::PhantomData<T> 是一种零大小、最小对齐的类型,出于协变性 (variance)析构检查 (drop check)自动 trait (auto traits) 的目的,它被视为拥有一个 T

运算符 trait

std::opsstd::cmp 中的 trait 用于重载运算符索引表达式调用表达式

DerefDerefMut

除了重载一元 * 运算符外,DerefDerefMut 还用于方法解析 (method resolution)解引用强制转换 (deref coercions)

Drop

Drop trait 提供一个析构器 (destructor),它在每次此类型的值被销毁时运行。

Copy

Copy trait 改变了实现它的类型的语义。

类型实现 Copy 的值在赋值时会被复制而不是移动。

Copy 只能为不实现 Drop 且其所有字段都为 Copy 的类型实现。对于 enum,这意味着所有变体的所有字段都必须是 Copy。对于 union,这意味着所有变体都必须是 Copy

Copy 由编译器为以下类型实现

  • 不捕获任何值或只捕获 Copy 类型值的闭包

Clone

Clone trait 是 Copy 的超 trait (supertrait),因此它也需要编译器生成的实现。

它由编译器为以下类型实现

  • 具有内建 Copy 实现的类型(见上文)
  • 只捕获 Clone 类型值或不从环境捕获任何值的闭包

Send

Send trait 表明此类型的值可以安全地从一个线程发送到另一个线程。

Sync

Sync trait 表明此类型的值可以安全地在多个线程之间共享。

此 trait 必须为用于不可变 static的所有类型实现。

Termination

Termination trait 表明主函数 (main function)测试函数 (test functions) 的可接受返回类型。

自动 trait

SendSyncUnpinUnwindSafeRefUnwindSafe trait 是自动 trait。自动 trait 具有特殊属性。

如果某个给定类型没有为自动 trait 显式编写实现或负面实现,则编译器会根据以下规则自动实现它

  • 如果 T 实现该 trait,则 &T&mut T*const T*mut T[T; n][T] 也实现该 trait。
  • 函数项类型和函数指针自动实现该 trait。
  • struct、enum、union 和 tuple 如果它们的所有字段都实现该 trait,则也实现该 trait。
  • 如果闭包捕获的所有类型都实现该 trait,则闭包也实现该 trait。通过共享引用捕获 T 并通过值捕获 U 的闭包会实现 &TU 都实现的任何自动 trait。

对于泛型类型(将上述内建类型视为对 T 泛型),如果存在泛型实现,则对于那些可能使用该实现但由于不满足必需的 trait 约束而不能使用的类型,编译器不会自动实现该 trait。例如,标准库为所有 TSync&T 实现了 Send;这意味着如果 TSend 但不是 Sync,则编译器不会为 &T 实现 Send

自动 trait 也可以有负面实现 (negative implementations),在标准库文档中表示为 impl !AutoTrait for T,它们会覆盖自动实现。例如,*mut TSend 有一个负面实现,因此即使 TSend*mut T 也不是 Send。目前没有稳定的方法来指定额外的负面实现;它们只存在于标准库中。

自动 trait 可以作为额外的约束 (bound) 添加到任何trait 对象中,即使通常只允许一个 trait。例如,Box<dyn Debug + Send + UnwindSafe> 是一个有效的类型。

Sized

Sized trait 表明此类型的大小在编译时是已知的;也就是说,它不是一个动态大小类型 (dynamically sized type)

类型参数(trait 中的 Self 除外)默认为 Sized关联类型也默认为 Sized

Sized 总是由编译器自动实现,而不是通过实现项 (implementation items) 实现。

这些隐式的 Sized 约束 (bounds) 可以通过使用特殊的 ?Sized 约束来放宽。