PhantomData<T>是一个零大小类型的标记结构体。
作用:
- 并不使用的类型;
- 型变;
- 标记拥有关系;
- 自动trait实现(send/sync);
并不使用的类型
生命周期
struct Slice<'a, T> {
start: *const T,
end: *const T,
}
然而,因为'a在结构体中未使用,所以它是无界的。在结构定义中禁止无限生命周期和类型。
修改如下:
use std::marker;
struct Iter<'a, T: 'a> {
ptr: *const T,
end: *const T,
_marker: marker::PhantomData<&'a T>,
}
类型
pub struct RetryableSendCh<T, C: Sender<T>> {
ch: C,
name: &'static str,
marker: PhantomData<T>,
}
标记拥有关系
struct Vec<T> {
data: *const T, // *const for variance!
len: usize,
cap: usize,
}
原生指针不具有所有权语义,drop检查器将认为Vec<T>
不具有类型T的任何值。这将反过来使得它不需要担心Vec在其析构函数中丢弃任何T
。但是有可能T
被提前释放。为了drop检查器认为vec一定拥有了T
的数据,修改如下:
use std::marker;
struct Vec<T> {
data: *const T, // *const for variance!
len: usize,
cap: usize,
_marker: marker::PhantomData<T>,
}
型变
- 不变
如果不能将一个类型替换为另一个类型,那么这个类型就称之为:不变。
- 逆变
可以由其基类替换。
- 协变
可以由其派生类型替换。
PhantomData
模式表
这是一张PhantomData
可以使用的所有方法的表格:
Phantom type | 'a |
T |
---|---|---|
PhantomData<T> |
- | variant (with drop check) |
PhantomData<&'a T> |
variant | variant |
PhantomData<&'a mut T> |
variant | invariant |
PhantomData<*const T> |
- | variant |
PhantomData<*mut T> |
- | invariant |
PhantomData<fn(T)> |
- | contravariant (*) |
PhantomData<fn() -> T> |
- | variant |
PhantomData<fn(T) -> T> |
- | invariant |
PhantomData<Cell<&'a ()>> |
invariant | - |
(*)如果逆变被废除,这将是不变的。