特殊类型和特征

Rust 编译器知道标准库中存在的某些类型和特征。本章记录这些类型和特征的特殊功能。

Box<T>

Box<T> 具有 Rust 当前不允许用户定义的类型使用的一些特殊功能。

  • Box<T>解引用运算符 产生一个可以从中移动的位置。这意味着 * 运算符和 Box<T> 的析构函数是语言内置的。
  • 方法 可以将 Box<Self> 作为接收者。
  • 可以在 T 所在的 crate 中为 Box<T> 实现 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> 是一个零大小、最小对齐的类型,为了 方差drop check自动 trait 的目的,它被认为拥有一个 T

运算符 Trait

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

DerefDerefMut

除了重载一元 * 运算符之外,DerefDerefMut 还用于 方法解析解引用强制转换

Drop

Drop trait 提供一个 析构函数,在要销毁此类型的值时运行。

Copy

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

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

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

Clone

Clone trait 是 Copy 的超 trait,因此它也需要编译器生成的实现。编译器为以下类型实现它

  • 具有内置 Copy 实现的类型(参见上文)
  • Clone 类型的 元组
  • 仅捕获 Clone 类型的值或不从环境中捕获任何值的 闭包

Send

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

Sync

Sync trait 表示此类型的值可以安全地在多个线程之间共享。必须为在不可变 static 中使用的所有类型实现此 trait。

Termination

Termination trait 表示 main 函数测试函数 的可接受的返回类型。

自动 trait

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

如果未为给定类型的自动 trait 写出显式实现或负实现,则编译器会根据以下规则自动实现它

  • 如果 T 实现 trait,则 &T&mut T*const T*mut T[T; n][T] 实现该 trait。
  • 函数项类型和函数指针会自动实现该 trait。
  • 如果结构体、枚举、联合体和元组的所有字段都实现该 trait,则它们会实现该 trait。
  • 如果闭包的所有捕获类型都实现该 trait,则闭包会实现该 trait。通过共享引用捕获 T 和通过值捕获 U 的闭包,会实现 &TU 都实现的任何自动 trait。

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

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

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

Sized

Sized trait 表示此类型的大小在编译时已知;也就是说,它不是 动态大小类型类型参数(除了 trait 中的 Self)默认是 Sized 的,关联类型 也是如此。Sized 始终由编译器自动实现,而不是由 实现项 实现。这些隐式的 Sized 边界可以通过使用特殊的 ?Sized 边界来放松。