原生 traits 和类型表示类型的基本属性。
Rust 类型可以根据其固有属性以各种有用的方式进行分类。 这些分类表示为 traits。
原生 traits 和类型表示类型的基本属性。
Rust 类型可以根据其固有属性以各种有用的方式进行分类。 这些分类表示为 traits。
https://doc.rust-lang.org/std/marker/trait.Sized.html
pub trait Sized { }
在编译时已知常量大小的类型。
所有类型参数的隐含边界均为 Sized
。如果不合适,可以使用特殊语法 ?Sized
删除此绑定。
struct Foo<T>(T);
struct Bar<T: ?Sized>(T);
// struct FooUse(Foo<[i32]>); // 错误:没有为 [i32] 实现大小调整
struct BarUse(Bar<[i32]>); // OK
一个例外是 trait 的隐式 Self
类型。 trait 没有隐式 Sized
绑定,因为它与 trait 对象 不兼容,根据定义,trait 需要与所有可能的实现者一起使用,因此可以为任意大小。
尽管 Rust 允许您将 Sized
绑定到 trait,但是以后您将无法使用它来形成 trait 对象:
trait Foo { }
trait Bar: Sized { }
struct Impl;
impl Foo for Impl { }
impl Bar for Impl { }
let x: &dyn Foo = &Impl; // OK
// let y: &dyn Bar = &Impl; // 错误:无法将 trait `Bar` 创建成对象
备注:trait object的要求之一就是trait不能是Sized,这也可以作为禁止将某个trait用作trait object的方式
https://github.com/rust-lang/rust/blob/master/library/core/src/marker.rs
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "sized"]
#[rustc_on_unimplemented(
message = "the size for values of type `{Self}` cannot be known at compilation time",
label = "doesn't have a size known at compile-time"
)]
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
#[rustc_specialization_trait]
pub trait Sized {
// Empty.
}
Sized trait 非常重要,编译期用它来识别在编译期确定大小的类型。
#[lang = "sized"]
pub trait Sized {
// Empty.
}
Sized trait 是空 trait,仅仅作为标签 trait 供编译期使用。真正起"打标签"作用的是属性 #[lang = "sized"]
。该属性lang表示Sized trait供rust语言本身使用,声明为 “sized”,称为语言项(Lang Item)。
rust语言中大部分类型都是默认 Sized ,如果需要使用动态大小类型,则需要改为 <T: ?Sized>
限定。
struct Foo<T>(T);
struct Bar<T: ?Sized>(T);
Sized 标记的是在编译期可确定大小的类型
Unsized 标记的是动态大小类型,在编译期无法确定其大小
目前rust中的动态类型有 trait 和 [T]
其中 [T] 代表一定数量的T在内存中的一次排列,但不知道具体的数量,所以大小是未知的。
?Sized 标记的类型包含了 Sized 和 Unsized 所标识的两种类型。
所以泛型结构体 struct Bar<T: ?Sized>(T);
支持编译期可确定大小类型和动态大小类型两种类型。
&[T]
或者 &trait
https://doc.rust-lang.org/std/marker/trait.Unsize.html
pub trait Unsize<T: ?Sized> {}
可以是未定义大小的类型也可以是动态大小的类型。
例如,按大小排列的数组类型 [i8; 2]
实现 Unsize<[i8]>
和 Unsize<dyn fmt::Debug>
。
Unsize
的所有实现均由编译器自动提供。
Unsize
为以下目的实现:
[T; N]
是 Unsize<[T]>
当T: Trait
时 T
为 Unsize<dyn Trait>
Foo<..., T, ...>
是 Unsize<Foo<..., U, ...>>
,如果
T: Unsize<U>
Foo
的最后一个字段具有涉及 T
的类型T
不属于任何其他字段的类型Bar<T>: Unsize<Bar<U>>
, 如果 Foo
的最后一个字段的类型为 Bar<T>
Unsize
与 ops::CoerceUnsized
一起使用可允许 “user-defined” 容器 (例如 Rc
包含动态大小的类型。 有关更多详细信息,请参见 DST coercion RFC 和 the nomicon entry on coercion。
https://github.com/rust-lang/rust/blob/master/library/core/src/marker.rs
#[unstable(feature = "unsize", issue = "27732")]
#[lang = "unsize"]
pub trait Unsize<T: ?Sized> {
// Empty.
}
https://doc.rust-lang.org/std/marker/trait.Copy.html
pub trait Copy: Clone { }
只需复制位即可复制其值的类型。
默认情况下,变量绑定具有 move语义
。换句话说:
#[derive(Debug)]
struct Foo;
let x = Foo;
let y = x;
// `x` 已移至 `y`,因此无法使用
// println!("{:?}", x); // error: use of moved value
但是,如果类型实现 Copy
,则它具有复制语义:
// 我们可以派生一个 `Copy` 实现。
// `Clone` 也是必需的,因为它是 `Copy` 的父特征。
#[derive(Debug, Copy, Clone)]
struct Foo;
let x = Foo;
let y = x;
// `y` 是 `x` 的副本
println!("{:?}", x); // A-OK!
重要的是要注意,在这两个示例中,唯一的区别是分配后是否允许您访问 x
。 在后台,复制(copy)和移动(move)都可能导致将位复制到内存中,尽管有时会对其进行优化。
Copy
?有两种方法可以在您的类型上实现 Copy
。最简单的是使用 derive
:
#[derive(Copy, Clone)]
struct MyStruct;
您还可以手动实现 Copy
和 Clone
:
struct MyStruct;
impl Copy for MyStruct { }
impl Clone for MyStruct {
fn clone(&self) -> MyStruct {
*self
}
}
两者之间的区别很小: derive
策略还将 Copy
绑定在类型参数上,这并不总是需要的。
Copy
和 Clone
有什么区别?复制是隐式发生的,例如作为分配 y = x
的一部分。Copy
的行为不可重载; 它始终是简单的按位复制。
克隆是一个明确的动作 x.clone()
。Clone
的实现可以提供安全复制值所需的任何特定于类型的行为。 例如,用于 String
的 Clone
的实现需要在堆中复制指向字符串的缓冲区。 String
值的简单按位副本将仅复制指针,从而导致该行向下双重释放。 因此,String
是 Clone
,但不是 Copy
。
Clone
是 Copy
的父特征,因此 Copy
的所有类型也必须实现 Clone
。 如果类型为 Copy
,则其 Clone
实现仅需要返回 *self
(请参见上面的示例)。
Copy
?如果类型的所有组件都实现 Copy
,则它可以实现 Copy
。例如,此结构体可以是 Copy
:
#[derive(Copy, Clone)]
struct Point {
x: i32,
y: i32,
}
一个结构体可以是 Copy
,而 i32
是 Copy
,因此 Point
有资格成为 Copy
。 相比之下,考虑
struct PointList {
points: Vec<Point>,
}
结构体 PointList
无法实现 Copy
,因为 Vec
不是 Copy
。如果尝试派生 Copy
实现,则会收到错误消息:
the trait `Copy` may not be implemented for this type; field `points` does not implement `Copy`
共享引用 (&T
) 也是 Copy
,因此,即使类型中包含不是 *Copy
类型的共享引用 T
,也可以是 Copy
。 考虑下面的结构体,它可以实现 Copy
,因为它从上方仅对我们的非 Copy 类型 PointList
持有一个 shared 引用:
#[derive(Copy, Clone)]
struct PointListWrapper<'a> {
point_list_ref: &'a PointList,
}
Copy
?某些类型无法安全复制。例如,复制 &mut T
将创建一个别名可变引用。 复制 String
将重复管理 String
缓冲区,从而导致双重释放。
概括后一种情况,任何实现 Drop
的类型都不能是 Copy
,因为它除了管理自己的 size_of::
字节外还管理一些资源。
果您尝试在包含非 Copy
数据的结构或枚举上实现 Copy
,则会收到 E0204 错误。
Copy
?一般来说,如果您的类型可以实现 Copy
,则应该这样做。 但是请记住,实现 Copy
是您类型的公共 API 的一部分。 如果该类型将来可能变为非 Copy
,则最好现在省略 Copy
实现,以避免 API 发生重大更改。
除下面列出的实现者外,以下类型还实现 Copy
:
fn() -> i32
)Copy
(例如 [i32; 123456]
),则所有大小的数组类型Copy
(例如 ()
,(i32, bool)
),则为元组类型Copy
。 请注意,由共享引用捕获的变量始终实现 Copy
(即使引用对象没有实现),而由变量引用捕获的变量从不实现 Copy
。https://github.com/rust-lang/rust/blob/master/library/core/src/marker.rs
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "copy"]
#[rustc_unsafe_specialization_marker]
pub trait Copy: Clone {
// Empty.
}
原始类型的Copy的实现。
无法在Rust中描述的实现是在 rustc_trait_selection 中的 traits::SelectionContext::copy_clone_conditions()
中实现。
mod copy_impls {
use super::Copy;
macro_rules! impl_copy {
($($t:ty)*) => {
$(
#[stable(feature = "rust1", since = "1.0.0")]
impl Copy for $t {}
)*
}
}
impl_copy! {
usize u8 u16 u32 u64 u128
isize i8 i16 i32 i64 i128
f32 f64
bool char
}
#[unstable(feature = "never_type", issue = "35121")]
impl Copy for ! {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Copy for *const T {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Copy for *mut T {}
/// Shared references can be copied, but mutable references *cannot*!
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Copy for &T {}
}
copy trait 用来标识可以按位复制其值的类型,按位复制等价于c语言中的 memcpy。
pub trait Copy: Clone { }
copy trait 继承自 clone trait,意味着要实现 Copy trait 的类型,必须实现 Clone trait 中定义的方法。
要实现 Copy trait,就必须同时实现 Clone trait。
struct MyStruct;
impl Copy for MyStruct { }
impl Clone for MyStruct {
fn clone(&self) -> MyStruct {
*self
}
}
rust提供了更方便的 derive 属性:
#[derive(Copy, Clone)]
struct MyStruct;
copy 的行为是隐式行为,开发者不能重载 Copy 行为,它永远都是一个简单的位复制。
并非所有的类型都可以实现 Copy trait。
https://github.com/rust-lang/rust/blob/master/library/core/src/marker.rs
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "send_trait")]
#[rustc_on_unimplemented(
message = "`{Self}` cannot be sent between threads safely",
label = "`{Self}` cannot be sent between threads safely"
)]
pub unsafe auto trait Send {
// empty.
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Send for *const T {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Send for *mut T {}
https://doc.rust-lang.org/std/marker/trait.Send.html
pub unsafe auto trait Send { }
可以跨线程边界传输的类型。
当编译器确定适当时,会自动实现此 trait。
非 Send
类型的一个示例是引用计数指针 rc::Rc
。 如果两个线程试图克隆指向相同引用计数值的 Rc
,它们可能会同时尝试更新引用计数,这是 未定义行为 因为 Rc
不使用原子操作。
它的表亲 sync::Arc
确实使用原子操作 (产生一些开销),因此它是 Send
。
有关更多详细信息,请参见 the Nomicon。
rust 提供了 Send 和 Sync 两个标签 trait,他们是 rust 无数据竞争并发的基石。
有了这两个标签,就可以把rust中所有的类型归为两类:
在配合所有权机制,带来的效果就是,rust 能够在编译期就检查出数据竞争的隐患,而不需要到运行时再排查。
# 备注:这行代码在 marker.rs 中已经找不到了,不知道
# 为所有类型实现 Send
unsafe impl Send for .. {}
#[stable(feature = "rust1", since = "1.0.0")]
# 使用 !Send 语法排除 *const T 和 *mut T
impl<T: ?Sized> !Send for *const T {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Send for *mut T {}
https://doc.rust-lang.org/nomicon/send-and-sync.html
不过,并不是所有的东西都服从于继承的可变性。有些类型允许你在内存中对一个位置有多个别名,同时对其进行突变。除非这些类型使用同步化来管理这种访问,否则它们绝对不是线程安全的。Rust通过Send和Sync特性捕捉到这一点。
&T
是 Send 时,T 是 Sync)。Send 和 Sync 是Rust的并发故事的基础。因此,存在大量的特殊工具来使它们正常工作。首先,它们是不安全的特性。这意味着它们的实现是不安全的,而其他不安全的代码可以认为它们是正确实现的。由于它们是标记性的特征(它们没有像方法那样的关联项),正确实现仅仅意味着它们具有实现者应该具有的内在属性。不正确地实现 Send 或 Sync 会导致未定义行为。
Send 和 Sync 也是自动派生的特性。这意味着,与其它特质不同,如果一个类型完全由 Send 或 Sync 类型组成,那么它就是 Send 或 Sync。几乎所有的基元都是 Send 和 Sync,因此,几乎所有你将与之交互的类型都是 Send 和 Sync。
主要的例外情况包括:
Rc 和 UnsafeCell 从根本上说不是线程安全的:它们启用了非同步的共享可变体状态。然而,严格来说,原始指针被标记为线程不安全,更像是一种提示。对原始指针做任何有用的事情都需要对其进行解引用,这已经是不安全的了。从这个意义上说,人们可以争辩说,将它们标记为线程安全是 “好的”。
然而,重要的是,它们不是线程安全的,以防止包含它们的类型被自动标记为线程安全的。这些类型有非实质性的未跟踪的所有权,它们的作者不可能认真考虑线程安全问题。在Rc的例子中,我们有一个包含 *mut
的类型的好例子,它绝对不是线程安全的。
如果需要的话,那些没有自动派生的类型可以简单地实现它们。
struct MyBox(*mut u8);
unsafe impl Send for MyBox {}
unsafe impl Sync for MyBox {}
在极其罕见的情况下,一个类型被不适当地自动派生为Send或Sync,那么我们也可以不实现Send和Sync。
#![feature(negative_impls)]
// I have some magic semantics for some synchronization primitive!
struct SpecialThreadToken(u8);
impl !Send for SpecialThreadToken {}
impl !Sync for SpecialThreadToken {}
注意,就其本身而言,不可能错误地派生出 Send 和 Sync。只有那些被其他不安全代码赋予特殊含义的类型才有可能通过错误的 Send 或 Sync 引起麻烦。
大多数对原始指针的使用应该被封装在一个足够的抽象后面,以便 Send 和 Sync 可以被派生。例如,所有Rust的标准集合都是 Send 和 Sync(当它们包含Send和Sync类型时),尽管它们普遍使用原始指针来管理分配和复杂的所有权。同样地,大多数进入这些集合的迭代器都是Send和Sync的,因为它们在很大程度上表现为进入集合的 &
或 &mut
。
由于各种原因,Box被编译器实现为它自己的特殊内在类型,但是我们可以自己实现一些具有类似行为的东西,看看什么时候实现 Send 和 Sync 是合理的。让我们把它叫做 “Carton”。
我们先写代码,把一个分配在栈上的值,转移到堆上。
#![allow(unused)]
fn main() {
pub mod libc {
pub use ::std::os::raw::{c_int, c_void};
#[allow(non_camel_case_types)]
pub type size_t = usize;
extern "C" { pub fn posix_memalign(memptr: *mut *mut c_void, align: size_t, size: size_t) -> c_int; }
}
use std::{
mem::{align_of, size_of},
ptr,
};
struct Carton<T>(ptr::NonNull<T>);
impl<T> Carton<T> {
pub fn new(value: T) -> Self {
// Allocate enough memory on the heap to store one T.
assert_ne!(size_of::<T>(), 0, "Zero-sized types are out of the scope of this example");
let mut memptr = ptr::null_mut() as *mut T;
unsafe {
let ret = libc::posix_memalign(
(&mut memptr).cast(),
align_of::<T>(),
size_of::<T>()
);
assert_eq!(ret, 0, "Failed to allocate or invalid alignment");
};
// NonNull is just a wrapper that enforces that the pointer isn't null.
let mut ptr = unsafe {
// Safety: memptr is dereferenceable because we created it from a
// reference and have exclusive access.
ptr::NonNull::new(memptr.cast::<T>())
.expect("Guaranteed non-null if posix_memalign returns 0")
};
// Move value from the stack to the location we allocated on the heap.
unsafe {
// Safety: If non-null, posix_memalign gives us a ptr that is valid
// for writes and properly aligned.
ptr.as_ptr().write(value);
}
Self(ptr)
}
}
}
这不是很有用,因为一旦我们的用户给了我们一个值,他们就没有办法访问它。Box实现了 Deref
和 DerefMut
,这样你就可以访问内部的值。让我们来做这件事。
#![allow(unused)]
fn main() {
use std::ops::{Deref, DerefMut};
struct Carton<T>(std::ptr::NonNull<T>);
impl<T> Deref for Carton<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe {
// Safety: The pointer is aligned, initialized, and dereferenceable
// by the logic in [`Self::new`]. We require writers to borrow the
// Carton, and the lifetime of the return value is elided to the
// lifetime of the input. This means the borrow checker will
// enforce that no one can mutate the contents of the Carton until
// the reference returned is dropped.
self.0.as_ref()
}
}
}
impl<T> DerefMut for Carton<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
// Safety: The pointer is aligned, initialized, and dereferenceable
// by the logic in [`Self::new`]. We require writers to mutably
// borrow the Carton, and the lifetime of the return value is
// elided to the lifetime of the input. This means the borrow
// checker will enforce that no one else can access the contents
// of the Carton until the mutable reference returned is dropped.
self.0.as_mut()
}
}
}
}
最后,让我们考虑一下我们的Carton是否是Send和Sync。有些东西可以安全地成为 “Send”,除非它与其他东西共享可变的状态而不对其进行排他性访问。每个Carton都有一个唯一的指针,所以我们很好。
// Safety: No one besides us has the raw pointer, so we can safely transfer the
// Carton to another thread if T can be safely transferred.
unsafe impl<T> Send for Carton<T> where T: Send {}
Sync如何?为了使Carton同步,我们必须强制规定,你不能写到存储在一个 &Carton
中的东西,而这个东西可以从另一个 &Carton中
读到或写入。由于你需要一个 &mut Carton
来写入指针,并且 borrow 检查器强制要求可变引用必须是独占的,所以Carton也不存在健全性问题,可以同步。
// Safety: Since there exists a public way to go from a `&Carton<T>` to a `&T`
// in an unsynchronized fashion (such as `Deref`), then `Carton<T>` can't be
// `Sync` if `T` isn't.
// Conversely, `Carton` itself does not use any interior mutability whatsoever:
// all the mutations are performed through an exclusive reference (`&mut`). This
// means it suffices that `T` be `Sync` for `Carton<T>` to be `Sync`:
unsafe impl<T> Sync for Carton<T> where T: Sync {}
当我们断言我们的类型是Send and Sync时,我们通常需要强制要求每个包含的类型都是Send and Sync。当编写行为像标准库类型的自定义类型时,我们可以断言我们有同样的要求。例如,下面的代码断言,如果同类型的Box是Send,那么Carton就是Send,在这种情况下,这就等于说T是Send。
unsafe impl<T> Send for Carton<T> where Box<T>: Send {}
现在,Carton
impl<T> Drop for Carton<T> {
fn drop(&mut self) {
unsafe {
libc::free(self.0.as_ptr().cast());
}
}
}
一个不发生这种情况的好例子是MutexGuard:注意它不是Send。MutexGuard的实现使用了一些库,这些库要求你确保你不会试图释放你在不同线程中获得的锁。如果你能够将MutexGuard发送到另一个线程,那么析构器就会在你发送它的线程中运行,这就违反了要求。MutexGuard仍然可以被同步,因为你能发送给另一个线程的只是一个&MutexGuard,而丢弃一个引用什么也做不了。
TODO:更好地解释什么可以或不可以是Send或Sync。仅仅针对数据竞赛就足够了吗?
备注: 没看懂。。。
https://doc.rust-lang.org/std/marker/trait.Sync.html
pub unsafe auto trait Sync { }
可以在线程之间安全共享引用的类型。
当编译器确定适当时,会自动实现此 trait。
精确的定义是:当且仅当 &T
是 Send
时,类型 T
才是 Sync
。 换句话说,如果在线程之间传递 &T
引用时没有 未定义的行为 (包括数据竞争) 的可能性。
正如人们所料,像 u8
和 f64
这样的原始类型都是 Sync
,包含它们的简单聚合类型也是如此,比如元组、结构体和枚举。 基本 Sync
类型的更多示例包括不可变类型 (例如 &T
) 以及具有简单继承的可变性的类型,例如 Box
,Vec
和大多数其他集合类型。
该定义的一个令人惊讶的结果是 &mut T
是 Sync
(如果 T
是 Sync
),即使看起来可能提供了不同步的可变的。 诀窍是,共享引用 (即 & &mut T
) 后面的可变引用将变为只读,就好像它是 & &T
一样。 因此,没有数据竞争的风险。
不是 Sync
的类型是具有非线程安全形式的 “内部可变性” 的类型,例如 Cell
和 RefCell
。 这些类型甚至允许通过不可变,共享引用来更改其内容。 例如,Cell
上的 set
方法采用 &self
,因此它仅需要共享的引用 &Cell
。 该方法不执行同步,因此 Cell
不能为 Sync
。
另一个非 Sync
类型的例子是引用计数指针 Rc
。 给定任何引用 &Rc
,您可以克隆新的 Rc
,以非原子方式修改引用计数。
对于确实需要线程安全的内部可变性的情况,Rust 提供 原子数据类型 以及通过 sync::Mutex
和 sync::RwLock
进行的显式锁定。 这些类型可确保任何可变的都不会引起数据竞争,因此类型为 Sync
。 同样,sync::Arc
提供了 Rc
的线程安全模拟。
任何具有内部可变性的类型还必须在 value(s) 周围使用 cell::UnsafeCell
包装器,该包装器可以通过共享的引用进行更改。 未定义的行为 无法做到这一点。 例如,从 &T
到 &mut T
的 transmute
无效。
有关 Sync
的更多详细信息,请参见 the Nomicon。
https://github.com/rust-lang/rust/blob/master/library/core/src/marker.rs
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "sync_trait")]
#[lang = "sync"]
#[rustc_on_unimplemented(
message = "`{Self}` cannot be shared between threads safely",
label = "`{Self}` cannot be shared between threads safely"
)]
pub unsafe auto trait Sync {
// Empty
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Sync for *const T {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Sync for *mut T {}
https://doc.rust-lang.org/std/marker/trait.Unpin.html
pub auto trait Unpin { }
固定后可以安全移动的类型。
Rust 本身没有固定类型的概念,并认为 move (例如,通过赋值或 mem::replace
始终是安全的。
Pin
类型代替使用,以防止在类型系统中移动。Pin<P<T>>
包装器中包裹的指针 P<T>
不能移出。 有关固定的更多信息,请参见 pin
module 文档。
为 T
实现 Unpin
trait 消除了固定该类型的限制,然后允许使用诸如 mem::replace
之类的功能将 T
从 Pin<P<T>>
中移出。
Unpin
对于非固定数据完全没有影响。 特别是,mem::replace
可以愉快地移动 !Unpin
数据 (它适用于任何 &mut T
,而不仅限于 T: Unpin
)。 但是,您不能对包装在 Pin<P<T>>
内的数据使用 mem::replace
,因为您无法获得所需的 &mut T
,并且 that 是使此系统正常工作的原因。
因此,例如,这只能在实现 Unpin
的类型上完成:
use std::mem;
use std::pin::Pin;
let mut string = "this".to_string();
let mut pinned_string = Pin::new(&mut string);
// 我们需要一个可变引用来调用 `mem::replace`。
// 我们可以通过 (implicitly) 调用 `Pin::deref_mut` 来获得这样的引用,但这仅是可能的,因为 `String` 实现了 `Unpin`。
mem::replace(&mut *pinned_string, "other".to_string());
trait 几乎针对每种类型自动实现。
https://github.com/rust-lang/rust/blob/master/library/core/src/marker.rs
#[stable(feature = "pin", since = "1.33.0")]
#[rustc_on_unimplemented(
note = "consider using `Box::pin`",
message = "`{Self}` cannot be unpinned"
)]
#[lang = "unpin"]
pub auto trait Unpin {}
/// A marker type which does not implement `Unpin`.
///
/// If a type contains a `PhantomPinned`, it will not implement `Unpin` by default.
#[stable(feature = "pin", since = "1.33.0")]
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct PhantomPinned;
#[stable(feature = "pin", since = "1.33.0")]
impl !Unpin for PhantomPinned {}
#[stable(feature = "pin", since = "1.33.0")]
impl<'a, T: ?Sized + 'a> Unpin for &'a T {}
#[stable(feature = "pin", since = "1.33.0")]
impl<'a, T: ?Sized + 'a> Unpin for &'a mut T {}
#[stable(feature = "pin_raw", since = "1.38.0")]
impl<T: ?Sized> Unpin for *const T {}
#[stable(feature = "pin_raw", since = "1.38.0")]
impl<T: ?Sized> Unpin for *mut T {}