结论:PhantomData<T> 是零大小的标记类型,让结构体"在类型系统层面表现得像持有一个 T",从而在丢弃检查(drop check)、自动 trait 推导、生命周期和型变上获得正确语义,而不占任何内存。手写 unsafe 抽象(自写 Vec、裸指针封装)时几乎必然用到。

展开:典型场景:1)裸指针封装——struct MyVec<T> { ptr: *mut T, ... } 里裸指针不参与 drop check 和型变推导,加 _marker: PhantomData<T> 告诉编译器"我拥有 T,析构时会 drop 它",借用检查才能发现 use-after-free。2)标记借用关系——PhantomData<&'a T> 表达"我逻辑上借用 T",让生命周期参与推导。3)控制 auto trait——PhantomData<Rc<()>> 使类型 !Send。4)携带型变信息——PhantomData<fn() -> T> 表示对 T 协变但不实际持有(常见于 FFI 句柄)。易错点:漏掉 PhantomData 的 unsafe 代码往往"能跑"但暗藏 UB,Miri 能抓出部分问题。

struct Iter<'a, T: 'a> {
    ptr: *const T,
    end: *const T,
    _marker: std::marker::PhantomData<&'a T>, // 表达借用与协变
}

追问方向:型变(协变/逆变/不变)三者的判定、PhantomData<fn(T)> 为何用于约束逆变。