special-types-and-traits.md
commit: fcdc0cab546c10921d66054be25c6afc9dd6b3bc
本章译文最后维护日期:2020-11-16
标准库中的某些类型和 trait 在 Rust 编译器中也直接能用。本章就阐述了这些类型和 trait 的特殊特性。
Box<T>
有一些特殊的特性,Rust 目前还不允许用户定义类型时使用。
Box<T>
的[解引用操作符]会产生一个可从中移出值的内存位置1。这(种特殊性)意味着应用在Box<T>
上的*
运算符和Box<T>
的析构函数都是语言内置的。- 方法可以使用
Box<Self>
作为接受者。 Box<T>
可以绕过孤儿规则(orphan rules),与T
在同一 crate 中实现同一 trait,其他泛型类型无法绕过。
std::cell::UnsafeCell<T>
用于内部可变性。它确保编译器不会对此类类型执行不正确的优化。它还能确保具有内部可变类型的静态(static
)项不会被放在标记为只读的内存中。
std::marker::PhantomData<T>
是一个零尺寸零的、最小对齐量的、被认为拥有(own) T
的类型,这个类型存在目的是应用在确定型变关系、销毁检查和自动trait 中的。
std::ops
和 std::cmp
中的 trait 看用于重载 Rust 的运算符/操作符、索引表达式和调用表达式。
除了重载一元 *
运算符外,Deref
和 DerefMut
也用于方法解析(method resolution)和利用 Deref
达成自动强转。
Drop
trait 提供了一个析构函数,每当要销毁此类型的值时就会运行它。
Copy
trait 改变实现它的类型的语义。其类型实现了 Copy
的值在赋值时将被复制而不是移动。
只能为未实现 Drop
trait 且字段都是 Copy
的类型实现 Copy
。2
对于枚举,这意味着所有变体的所有字段都必须是 Copy
的。
对于联合体,这意味着所有的变体都必须是 Copy
的。
Copy
已由编译器实现给了下述类型:
Clone
trait 是 Copy
的超类trait,所以它也需要编译器生成实现。它被编译器实现给了以下类型:
Send
trait 表明这种类型的值可以安全地从一个线程发送给另一个线程。
Sync
trait 表示在多个线程之间共享这种类型的值是安全的。必须为不可变静态(static
)项中使用的所有类型实现此 trait。
Send
、Sync
、Unpin
、UnwindSafe
和 RefUnwindSafe
trait 都是自动trait(auto traits)。自动trait 具有特殊的属性。
对于给定类型,如果没有为其显式实现或否定实现(negative implementation)某自动trait,那么编译器就会根据以下规则去自动此为类型实现该自动trait:
- 如果
T
实现了某自动trait,那&T
、&mut T
、*const T
、*mut T
、[T; n]
和[T]
也会实现此自动trait。 - 函数项类型(function item types)和函数指针会自动实现这些自动trait。
- 如果结构体、枚举、联合体和元组它们的所有字段都实现了这些自动trait,则它们本身也会自动实现这些自动trait。
- 如果闭包捕获的所有变量的类型都实现了这些自动trait,那么闭包会自动实现这些自动trait。一个闭包通过共享引用捕获了一个
T
,同时通过传值的方式捕获了一个U
,那么该闭包会自动实现&T
和U
所共同实现的那些自动trait。
对于泛型类型(上面的这些内置类型也算是建立在 T
上的泛型),如果泛型实现在当前已够用,则编译器不会再为其实现其他的自动trait,除非它们不满足必需的 trait约束。例如,标准库在 T
是 Sync
的地方都为 &T
实现了 Send
;这意味着如果 T
是 Send
,而不是 Sync
,编译器就不会为 &T
自动实现 Send
。
自动trait 也可以有否定实现,在标准库文档中表示为 impl !AutoTrait for T
,它覆盖了自动实现。例如,*mut T
有一个关于 Send
的否定实现,所以 *mut T
不是 Send
的,即使 T
是。目前还没有稳下来的方法来指定其他类型的否定实现;目前否定实现只能在标准库里可以稳定使用。3
自动trait 可以作为额外的约束添加到任何 trait对象上,尽管通常我们见到的 trait对象的类型名上一般只显示一个 trait。例如,Box<dyn Debug + Send + UnwindSafe>
就是一个有效的类型。
Sized
trait表明这种类型的尺寸在编译时是已知的;也就是说,它不是一个动态尺寸类型。类型参数默认是 Sized
的。Sized
总是由编译器自动实现,而不是由实现(implementation items)主动实现的。