Skip to content

Latest commit

 

History

History
90 lines (74 loc) · 2.41 KB

15. PhantomData.org

File metadata and controls

90 lines (74 loc) · 2.41 KB

参考

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, 完全可以忽略, 主要在编译时检查起作用, 就像真正拥有尖括号中类型的字段一样, 通常的作用如下:

  1. 引入一个相关但字段中不包含的 generic (可以是 lifetime, 也可以是普通 type)
  2. 做 drop check (详见 drop check)
  3. variance (informally 详见 variance)
  4. 可以引入特定类型来阻止实现 auto trait (当然也可以用 unstable 的 negative impl)

NOTE: 1 的问题部分可以用 generic method 解决

lifetime 例子

#![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 例子

详见 drop and drop check 章节

variance 例子

加入现在我们需要 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 字段这里会编译不通过
}

auto trait 的例子

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);
}