当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Rust PhantomData用法及代码示例


本文简要介绍rust语言中 Struct std::marker::PhantomData 的用法。

用法

pub struct PhantomData<T> where    T: ?Sized;

零大小的类型用于标记 “act like” 他们拥有 T 的东西。

向你的类型添加一个 PhantomData<T> 字段会告诉编译器你的类型表现得好像它存储了一个类型为 T 的值,即使它不是真的。在计算某些安全属性时使用此信息。

有关如何使用 PhantomData<T> 的更多 in-depth 说明,请参阅 the Nomicon

一个可怕的笔记👻👻👻

尽管它们都有可怕的名字,但PhantomData 和'phantom types' 是相关的,但并不完全相同。幻像类型参数只是一个从未使用过的类型参数。在 Rust 中,这经常会导致编译器报错,解决方案是通过 PhantomData 的方式添加 “dummy” 使用。

例子

未使用的生命周期参数

PhantomData 最常见的用例可能是具有未使用的生命周期参数的结构,通常作为某些不安全代码的一部分。例如,这是一个结构体 Slice ,它有两个 *const T 类型的指针,大概指向某个数组:

struct Slice<'a, T> {
    start: *const T,
    end: *const T,
}

目的是基础数据仅在生命周期内有效'a, 所以Slice不应该活得更久'a.但是,此意图未在代码中表达,因为没有使用生命周期'a因此不清楚它适用于哪些数据。我们可以通过告诉编译器采取行动来纠正这个问题仿佛 Slice结构包含一个引用&'a T

use std::marker::PhantomData;

struct Slice<'a, T: 'a> {
    start: *const T,
    end: *const T,
    phantom: PhantomData<&'a T>,
}

这反过来也需要注释 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,
    }
}

未使用的类型参数

有时会发生未使用的类型参数,这些参数指示结构是“tied” 的数据类型,即使该数据实际上并未在结构本身中找到。这是一个与 FFI 一起出现的示例。外部接口使用 *mut () 类型的句柄来引用不同类型的 Rust 值。我们使用包装句柄的结构ExternalResource 上的幻像类型参数来跟踪 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);
    }
}

所有权和掉落检查

添加类型为 PhantomData<T> 的字段表示您的类型拥有类型为 T 的数据。这反过来意味着当您的类型被删除时,它可能会删除一个或多个类型为 T 的实例。这与 Rust 编译器的 drop check 分析有关。

如果您的结构实际上不是自己的类型的数据T,最好使用引用类型,比如PhantomData<&'a T>(理想情况下)或PhantomData<*const T>(如果没有生命周期适用),以免表明所有权。

相关用法


注:本文由纯净天空筛选整理自rust-lang.org大神的英文原创作品 Struct std::marker::PhantomData。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。