特殊类型和 trait
Rust 编译器已知某些 标准库 中存在的类型和 trait 。 本节介绍这些类型和 trait 的特殊特性。
Box<T>
Box<T>
具有 Rust 目前不允许用户定义类型拥有的一些特殊特性。
Box<T>
的 解引用运算符 产生一个可以被移动的地址。 表示*
运算符及Box<T>
的析构函数是内置到语言中的。- 方法 可以以
Box<Self>
作为接收者。 - 在与
T
相同的 crate 中可以为Box<T>
实现 trait,而 孤儿规则 阻止了对其他泛型类型的实现。
Rc<T>
Arc<T>
Pin<P>
UnsafeCell<T>
std::cell::UnsafeCell<T>
用于 内部可变性 。
它确保了编译器对此类类型进行正确的优化,还确保带有内部可变性的类型的 static
条目 不会被放置在标记为只读的内存中。
PhantomData<T>
std::marker::PhantomData<T>
是一种零大小、最小对齐的类型。
从 协变性、丢弃检查 和 [自动 trait]auto traits 的角度来看,被视为拥有一个类型为 T
的实例。
运算符 trait
std::ops
和 std::cmp
中的 trait 用于重载 运算符 、 索引表达式 和 调用表达式 。
Deref
和 DerefMut
除了重载一元操作符 *
之外,Deref
和 DerefMut
还用于 方法解析 和 解引用强制转换。
Drop
Drop
trait 提供了一个 析构器 ,当该类型的值即将被销毁时运行。
Copy
Copy
trait 改变了实现它的类型的语义。实现 Copy
的类型的值在赋值时会被复制而不是移动。
只有不实现 Drop
trait 并且其所有字段都是 Copy
类型的类型才能实现 Copy
trait 。
对于枚举,意味着所有变体的所有字段都必须是 Copy
类型。
对于联合体,意味着所有变体都必须是 Copy
类型。
编译器为以下类型实现了 Copy
trait :
Clone
Clone
trait 是 Copy
的父级trait ,因此它也需要编译器生成的实现。编译器为以下类型实现了此 trait:
- 有内置
Copy
实现的类型 (见上文) Clone
类型的元组
Send
Send
trait 表明此类型的值可以安全地从一个线程发送到另一个线程。
Sync
Sync
trait 表明此类型的值可以安全地在多个线程之间共享。所有用于不可变 static
条目 的类型都必须实现此 trait 。
Termination
Termination
trait 指示 main 函数 和 test 函数 的可接受返回类型。
自动 trait
Send
、Sync
、Unpin
、UnwindSafe
和 RefUnwindSafe
trait 是 "自动 trait" 。
自动 trait 具有特殊的属性。如果对于给定类型的自动 trait 没有显式实现或否定实现 ,则编译器会根据以下规则自动实现:
- 如果类型
T
实现了 trait ,那么&T
&mut T
*const T
*mut T
[T; n]
和[T]
都会实现该 trait 。 - 函数条目类型和函数指针会自动实现该 trait 。
- 如果它们的所有字段都实现了该 trait ,则结构体、枚举、联合体和元组会实现该 trait 。
- 如果它们捕获的所有值的类型都实现了该 trait ,则闭包会实现该 trait 。
捕获一个 T
的共享引用和一个 U
的值的闭包会实现两个 &T
和 U
都实现的自动 trait 。
对于泛型类型 (将上面内置类型视为泛型的 T
),如果有通用实现,则编译器不会自动实现该 trait ,而是根据需要的 trait 约束为没有达到 trait 约束的类型实现。例如,标准库为所有 T
是 Sync
的 &T
实现了 Send
;这意味着,如果 T
是 Send
但不是 Sync
,则编译器不会为 &T
实现 Send
。
自动 trait 也可以有否定实现,在标准库文档中表示为 impl !AutoTrait for T
,它们覆盖了自动实现。例如, *mut T
有一个 Send
的否定实现,因此即使 T
是 Send
, *mut T
也不是 Send
。
目前没有稳定的方法指定额外的否定实现;它们只存在于标准库中。自动 trait 可以作为 trait 对象 的附加约束添加到任何 trait 中,尽管通常只允许一个 trait 。
例如,Box<dyn Debug + Send + UnwindSafe>
是一个有效的类型。
Sized
Sized
trait 表示这个类型在编译时大小是已知的,即不是 动态大小类型 。
类型参数 (除了trait 中的 Self
) 默认都是 Sized
的,关联类型也是。
Sized
trait 总是由编译器自动实现,而不是由 实现条目 实现的。
这些隐式的 Sized
约束可以通过使用特殊的 ?Sized
约束进行放宽。