特殊类型和 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>
Arc<T>
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::ops 和 std::cmp 中的 trait 用于重载运算符、索引表达式和调用表达式。
Deref 和 DerefMut
除了重载一元 * 运算符外,Deref 和 DerefMut 还用于方法解析 (method resolution) 和解引用强制转换 (deref coercions)。
Drop
Drop trait 提供一个析构器 (destructor),它在每次此类型的值被销毁时运行。
Copy
Copy trait 改变了实现它的类型的语义。
类型实现 Copy 的值在赋值时会被复制而不是移动。
Copy 只能为不实现 Drop 且其所有字段都为 Copy 的类型实现。对于 enum,这意味着所有变体的所有字段都必须是 Copy。对于 union,这意味着所有变体都必须是 Copy。
Copy 由编译器为以下类型实现
Copy类型的元组
- 不捕获任何值或只捕获
Copy类型值的闭包
Clone
Clone trait 是 Copy 的超 trait (supertrait),因此它也需要编译器生成的实现。
它由编译器为以下类型实现
- 具有内建
Copy实现的类型(见上文)
Clone类型的元组
- 只捕获
Clone类型值或不从环境捕获任何值的闭包
Send
Send trait 表明此类型的值可以安全地从一个线程发送到另一个线程。
Sync
Sync trait 表明此类型的值可以安全地在多个线程之间共享。
此 trait 必须为用于不可变 static 项的所有类型实现。
Termination
Termination trait 表明主函数 (main function) 和测试函数 (test functions) 的可接受返回类型。
自动 trait
Send、Sync、Unpin、UnwindSafe 和 RefUnwindSafe 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的闭包会实现&T和U都实现的任何自动 trait。
对于泛型类型(将上述内建类型视为对 T 泛型),如果存在泛型实现,则对于那些可能使用该实现但由于不满足必需的 trait 约束而不能使用的类型,编译器不会自动实现该 trait。例如,标准库为所有 T 是 Sync 的 &T 实现了 Send;这意味着如果 T 是 Send 但不是 Sync,则编译器不会为 &T 实现 Send。
自动 trait 也可以有负面实现 (negative implementations),在标准库文档中表示为 impl !AutoTrait for T,它们会覆盖自动实现。例如,*mut T 对 Send 有一个负面实现,因此即使 T 是 Send,*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 约束来放宽。