我知道这PhantomData是要消耗数据类型定义中的生命周期或类型参数,否则将不使用该参数。我最近在看的定义Rc在锈标准库,发现它似乎雇用PhantomData,但它看起来像T在同级领域正在被使用ptr作为NonNull<RcBox<T>>。文档说这NonNull是“ * mut T,但非零且协变”。并通过以下语句进一步扩展该定义:
与相比
*mut T,NonNull<T>T 与T协变。如果这对于您的用例而言是不正确的,则应PhantomData在类型中包括一些以提供不变性,例如PhantomData<Cell<T>>或PhantomData<&'a mut T>。
因此,它是否需要方差还是更多,因为NonNull它实际上是原始指针,PhantomData并且需要消耗消亡的生命,因为这个答案似乎暗示了这一点?
PhantomData用来告诉丢弃检查器丢弃Rc<T> 可能导致类型值的T丢弃。
当我们宣布可以删除type的值时T,删除检查器将确保所有生存期都T超过其struct自身。正是这种检查阻止了以下代码的编译。在这种情况下,Rcis 的通用参数PeekOnDrop<&'a u8>具有生命周期'a。
use std::{fmt, rc::Rc};
struct PeekOnDrop<T: fmt::Debug>(T);
impl<T: fmt::Debug> Drop for PeekOnDrop<T> {
fn drop(&mut self) {
println!("{:?}", self.0);
}
}
struct SelfReferential<'a> {
value: Box<u8>,
rc: Option<Rc<PeekOnDrop<&'a u8>>>,
}
fn main() {
let mut sr = SelfReferential {
rc: None,
value: Box::new(1),
};
sr.rc = Some(Rc::new(PeekOnDrop(&*sr.value)));
// `sr` would be dropped here, which could drop `value` before `rc`.
// The destructor of `PeekOnDrop` would then try to inspect the (dangling)
// reference, resulting in UB!
}
Run Code Online (Sandbox Code Playgroud)
有关此处的基本逻辑的完整说明,请参见nomicon,但请注意,如果没有PeekOnDrop,则前面的示例编译就可以了。这是因为Rc<T>在其Drop隐式中声明其通用参数T为#[may_dangle]。通过这样做,它承诺其Dropimpl不T对其拥有的值做任何事情,除非(可能)删除它。仅当drop checker递归检查Dropimpl PeekOnDrop并发现它可以访问时,T才会发生错误。
为了完整起见,这里是一个不确定的程序的一个例子是谎言由声称PeekOnDrop的DropIMPL不访问T使用#[may_dangle]。如果原始示例Rc未用于PhantomData声明它可能会降低的值,则同样的未定义行为也会显示出来T。