Struct core::marker::PhantomData
1.0.0 · source · pub struct PhantomData<T: ?Sized>;
Expand description
零大小的类型用来标记那些行为像它们拥有一个 T
的东西。
向您的类型添加 PhantomData<T>
字段将告诉编译器,您的类型的行为就像它存储了 T
类型的值一样,即使实际上并非如此。
在计算某些安全属性时会使用此信息。
有关如何使用 PhantomData<T>
的更深入的说明,请参见 the Nomicon。
一个可怕的笔记 👻👻👻
尽管它们都有可怕的名称,但 PhantomData
和 phantom 类型是相关的,但并不完全相同。phantom 类型参数只是从未使用过的类型参数。
在 Rust 中,这通常会导致编译器抱怨,而解决方案是通过 PhantomData
添加 “dummy” 用途。
Examples
未使用的生命周期参数
PhantomData
的最常见用例也许是具有未使用的生命周期参数的结构体,通常将其用作某些不安全代码的一部分。
例如,这是一个结构体 Slice
,它具有两个 *const T
类型的指针,大概指向某个地方的数组:
目的是底层数据仅在生命周期 'a
内有效,因此 Slice
不应超过 'a
。
但是,此意图未在代码中表达,因为没有使用生命周期 'a
,因此尚不清楚它适用于什么数据。
我们可以通过告诉编译器如果 Slice
结构体包含引用 &'a T
来执行 *as 来纠正此问题:
use std::marker::PhantomData;
struct Slice<'a, T> {
start: *const T,
end: *const T,
phantom: PhantomData<&'a T>,
}
Run这也反过来推断生命周期绑定 T: 'a
,表明 T
中的任何引用在生命周期 'a
内有效。
初始化 Slice
时,只需为字段 phantom
提供值 PhantomData
:
fn borrow_vec<T>(vec: &Vec<T>) -> Slice<'_, T> {
let ptr = vec.as_ptr();
Slice {
start: ptr,
end: unsafe { ptr.add(vec.len()) },
phantom: PhantomData,
}
}
Run未使用的类型参数
有时可能会发生未使用的类型参数,这些参数指示 “tied” 将结构体数据类型化的数据,即使该数据实际上不是在结构体本身中找到的也是如此。
这是 FFI 出现此情况的示例。
外部接口使用 *mut ()
类型的句柄来引用不同类型的 Rust 值。
我们使用包裹句柄的结构体 ExternalResource
上的 phantom
类型参数来跟踪 Rust 类型。
use std::marker::PhantomData;
use std::mem;
struct ExternalResource<R> {
resource_handle: *mut (),
resource_type: PhantomData<R>,
}
impl<R: ResType> ExternalResource<R> {
fn new() -> Self {
let size_of_res = mem::size_of::<R>();
Self {
resource_handle: foreign_lib::new(size_of_res),
resource_type: PhantomData,
}
}
fn do_stuff(&self, param: ParamType) {
let foreign_params = convert_params(param);
foreign_lib::do_stuff(self.resource_handle, foreign_params);
}
}
Run所有权和 drop 检测
PhantomData
与丢弃检查的确切交互可能会在 future中发生变化。
目前,添加 PhantomData<T>
类型的字段表示在极少数情况下您的类型拥有T
类型的数据。
这反过来又会影响 Rust 编译器的 drop check 分析。
有关确切规则,请参见 drop check 文档。
Layout
对于所有 T
,保证以下内容:
size_of::<PhantomData<T>>() == 0
align_of::<PhantomData<T>>() == 1