https://doc.rust-lang.org/nomicon/phantom-data.html https://doc.rust-lang.org/std/marker/struct.PhantomData.html https://users.rust-lang.org/t/looking-for-a-deeper-understanding-of-phantomdata/32477/4
在运行时就是一个 ZST, 完全可以忽略, 主要在编译时检查起作用, 就像真正拥有尖括号中类型的字段一样, 通常的作用如下:
- 引入一个相关但字段中不包含的 generic (可以是 lifetime, 也可以是普通 type)
- 做 drop check (详见 drop check)
- variance (informally 详见 variance)
- 可以引入特定类型来阻止实现 auto trait (当然也可以用 unstable 的 negative impl)
NOTE: 1 的问题部分可以用 generic method 解决
#![feature(ptr_sub_ptr)]
use std::marker::PhantomData;
#[derive(Debug)]
struct MySliceIter<'a, T: 'a> {
start: *const T,
end: *const T,
_marker: PhantomData<&'a T>,
}
impl<'a, T> MySliceIter<'a, T> {
fn new(slice: &[T]) -> MySliceIter<T> {
let start = &slice[0] as *const T;
MySliceIter {
start,
end: unsafe { start.add(slice.len()) },
_marker: PhantomData,
}
}
/// if no 'a bound in type, then we can not get a proper 'a
fn collect(self) -> Vec<&'a T> {
let n = unsafe { self.end.sub_ptr(self.start) };
let p = self.start;
(0..n).map(|x| unsafe { &*p.add(x) }).collect()
}
}
fn main() {
let data = vec![1, 2, 3];
let iter = MySliceIter::new(&data);
// data.remove(0); // can not remove the first item from 'data' if _marker exist
// dbg!(&iter.collect());
dbg!(&iter);
}
详见 drop and drop check 章节
加入现在我们需要 MySliceIter 是 invariant (当然这仅仅只是为了演示)
use std::marker::PhantomData;
struct MySliceIter<'a, T: 'a> {
start: *const T,
end: *const T,
_marker: PhantomData<&'a T>,
_should_invariant: PhantomData<std::cell::Cell<&'a T>>,
}
fn down_slice<'r, T>(t: MySliceIter<'static, T>) -> MySliceIter<'r, T> {
t // 如果有 _should_invariant 字段这里会编译不通过
}
use std::marker::PhantomData;
struct Foo<T> {
data: T,
_marker: PhantomData<*const T>
}
fn test_send<T: Send>(t: T) {}
fn main() {
let foo = Foo { data: 42, _marker: PhantomData };
test_send(foo);
}