结论:自动 trait 是编译器根据类型的组成自动推导实现的 trait——一个类型的所有字段都实现某 auto trait,该类型就自动实现它。Send(可安全移动到另一线程)、Sync(可安全被多线程共享引用)、Sized(编译期大小已知)都是 auto trait,另有 Unpin、UnwindSafe。
展开:推导规则举例:struct Foo { a: i32, b: Arc<Mutex<i32>> } 自动 Send + Sync;混入 Rc 或裸指针就自动失去二者,因为 Rc 的引用计数非原子。Sync 的精确定义是 &T: Send——把引用发到别的线程也安全。需要阻止自动推导时用负实现或幻影标记:PhantomData<*const ()> 让类型 !Send + !Sync,PhantomPinned 让类型 !Unpin。约束:auto trait 不能由用户给新类型手动 impl(unsafe impl Send 除外——向编译器承诺线程安全,承诺错了就是 UB)。易错点:&mut T 是 Send 但不是 Sync(共享可变引用的引用没有意义);Cell/RefCell 是 Send 但 !Sync。
use std::marker::PhantomData;
struct NotThreadSafe<T> {
data: T,
_marker: PhantomData<*const ()>, // !Send + !Sync
}
追问方向:unsafe impl Sync 的判断标准、为何 MutexGuard 曾经 !Send 及影响。