Struct std::marker::PhantomData 1.0.0[−][src]
pub struct PhantomData<T>
where
T: ?Sized;
Expand description
零大小的类型用来标记那些行为像它们拥有一个 T
的东西。
向您的类型添加 PhantomData<T>
字段将告诉编译器,您的类型的行为就像它存储了 T
类型的值一样,即使实际上并非如此。
在计算某些安全属性时会使用此信息。
有关如何使用 PhantomData<T>
的更深入的说明,请参见 the Nomicon。
一个可怕的笔记 👻👻👻
尽管它们都有可怕的名称,但 PhantomData
和 phantom 类型是相关的,但并不完全相同。phantom 类型参数只是从未使用过的类型参数。
在 Rust 中,这通常会导致编译器抱怨,而解决方案是通过 PhantomData
添加 “dummy” 用途。
Examples
未使用的生命周期参数
PhantomData
的最常见用例也许是具有未使用的生命周期参数的结构体,通常将其用作某些不安全代码的一部分。
例如,这是一个结构体 Slice
,它具有两个 *const T
类型的指针,大概指向某个地方的数组:
struct Slice<'a, T> { start: *const T, end: *const T, }Run
目的是基础数据仅对生命周期 'a
有效,因此 Slice
不应超过 'a
。
但是,此意图未在代码中表达,因为没有使用生命周期 'a
,因此尚不清楚它适用于什么数据。
我们可以通过告诉编译器如果 Slice
结构体包含引用 &'a T
来执行 *as 来纠正此问题:
use std::marker::PhantomData; struct Slice<'a, T: 'a> { 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<T>
类型的字段表示您的类型拥有 T
类型的数据。反过来,这意味着丢弃您的类型时,它可能会丢弃一个或多个 T
类型的实例。
这与 Rust 编译器的 drop check 分析有关。
如果您的结构体实际上并不 拥有T
类型的数据,则最好使用引用类型,例如 PhantomData<&'a T>
(ideally) 或 PhantomData<*const T>
(如果没有生命周期适用),以免表示所有权。
Trait Implementations
返回类型的 “default value”。 Read more