Special types and traits

特殊类型和 trait

special-types-and-traits.md
commit: 330ef9569444a7414633ba08cf5090da312f1f18
本章译文最后维护日期:2024-05-02

标准库中的某些类型和 trait 在 Rust 编译器中也直接能用。本章就阐述了这些类型和 trait 的特殊特性。

Box<T>

Box<T> 有一些特殊的特性,Rust 目前还不允许用户定义类型时使用。

  • Box<T> 的[解引用操作符]会产生一个可从中移出值的内存位置1。这(种特殊性)意味着应用在 Box<T> 上的 *运算符和 Box<T> 的析构函数都是语言内置的。
  • 方法可以使用 Box<Self> 作为接受者。
  • Box<T> 可以绕过孤儿规则(orphan rules),与 T 在同一 crate 中实现同一 trait,其他泛型类型无法绕过。

Rc<T>

方法可以使用 Rc<Self> 作为接受者。

Arc<T>

方法可以使用 Arc<Self> 作为接受者。

Pin<P>

方法可以使用 Pin<P> 作为接受者。

UnsafeCell<T>

std::cell::UnsafeCell<T> 用于内部可变性。它确保编译器不会对此类类型执行不正确的优化。它还能确保具有内部可变类型的静态(static)项不会被放在标记为只读的内存中。

PhantomData<T>

std::marker::PhantomData<T> 是一个零内存宽度零的、最小对齐量的、被认为拥有(own) T 的类型,这个类型存在目的是应用在确定型变关系、销毁检查自动trait 中的。

Operator Traits

运算符/操作符trait

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

Deref and DerefMut

除了重载一元 *运算符外,DerefDerefMut 也用于方法解析(method resolution)利用 Deref 达成自动强转

Drop

Drop trait 提供了一个析构函数,每当要销毁此类型的值时就会运行它。

Copy

Copy trait 改变实现它的类型的语义。其类型实现了 Copy 的值在赋值时将被复制而不是移动。

只能为未实现 Drop trait 且字段都是 Copy 的类型实现 Copy2
对于枚举,这意味着所有变体的所有字段都必须是 Copy 的。
对于联合体,这意味着所有的变体都必须是 Copy 的。

Copy 已由编译器实现给了下述类型:

  • Copy类型的元素组成的元组
  • 函数指针
  • [函数项][function item]
  • 不捕获环境变量或只捕获 Copy类型变量的闭包

Clone

Clone trait 是 Copy 的超类trait,所以它也需要编译器生成实现。它被编译器实现给了以下类型:

  • 实现了内置的 Copy trait 的类型(见上面)
  • Clone 类型的元素组成的元组
  • Closures 仅捕获环境中的 Clone类型的值或不捕获值时

Send

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

Sync

Sync trait 表示在多个线程之间共享这种类型的值是安全的。必须为不可变静态(static)项中使用的所有类型实现此 trait。

Termination

Termination trait 表示 main函数test函数 那些可被接受的返回类型。

Auto traits

SendSyncUnpinUnwindSafeRefUnwindSafe 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,那么该闭包会自动实现 &TU 所共同实现的那些自动trait。

对于泛型类型(上面的这些内置类型也算是建立在 T 上的泛型),如果泛型实现在当前已够用,则编译器不会再为其实现其他的自动trait,除非它们不满足必需的 trait约束。例如,标准库在 TSync 的地方都为 &T 实现了 Send;这意味着如果 TSend,而不是 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

Sized trait表明这种类型的内存宽度在编译时是已知的;也就是说,它不是一个动态内存宽度类型类型参数 (除了 trait 中的Self)和关联类型默认是 Sized 的。 Sized 总是由编译器自动实现,而不是由实现(implementation items)主动实现的。 这些隐式的 Sized约束可以通过指定 ?Sized约束来放宽约束。

1

这里是相对普通的借用/引用来说,普通的借用/引用对指向的内存位置不拥有所有权,所以无法从中移出值。

2

实现 Drop trait 的类型只能是使用移动语义(move)的类型。

3

标准库外使用需要打开特性 #![feature(negative_impls)]