當前位置: 首頁>>編程示例 >>用法及示例精選 >>正文


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。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。