Rust 中的 PhantomData 类型用法

PhantomData type usage in rust

我在查看一些 Rust 源代码时发现了一种名为 PhantomData 的数据类型。我正在浏览 Rust 文档并在互联网上搜索了很多。但是,我无法理解这种数据类型在 rust 中的实际用途。如果可能的话,有人能用简单的方式向我解释一下吗?

pub struct GPIOD {
   _marker: PhantomData<*const ()>,
}

PhantomData 结构旨在向编译器发出信号,表明正在以某种对编译器透明的方式使用类型或生命周期。

引用文档:

Adding a PhantomData field to your type tells the compiler that your type acts as though it stores a value of type T, even though it doesn't really. This information is used when computing certain safety properties.

例如,如果我们查看切片 [T] 的迭代器类型:std::slice::Iter<'a, T> and its declaration using the src button 我们会看到它实际上是这样声明的:

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

std 经常使用指针算法来使优化更容易获得(尽管 支持在用户代码中使用指针算法)。在这种情况下,我们需要确保由两个原始指针(没有生命周期)指向的数据比结构更有效,所以 我们保留一个PhantomData<&'a T>告诉编译器表现得好像 Iter 拥有一个 &'a T 因此对其执行生命周期规则。

除了另一个答案,我想补充一个例子。如另一个答案所述,PhantomData 允许在 2 个结构之间添加任意生命周期依赖性。

假设您有一个结构体,用于管理带有消息接收器的日志记录工具,以及一个表示实际记录器的结构体,用于向管理器发送消息。虽然 logger 不直接依赖于 manager,但是 manager 必须比 logger 长寿以防止发送错误。

天真的代码不会在 2 个结构之间创建任何依赖关系:

struct LogManager {
    // ...
}

impl LogManager {
    fn logger(&self) -> Logger {
        // returns a fresh `Logger` that holds no reference to `LogManager`...
    }
}

struct Logger {
    // ...
}

现在,如果 Logger 持有一个幻象引用,我们可以在 2 个结构之间强制建立依赖关系:

struct Logger<'a> {
    // ...
    _marker: PhantomData<'a ()>,
}

并且在 impl 块中:

impl LogManager {
    fn logger(&self) -> Logger {
        Logger {
            // ...
            // Here, `Logger` will have a lifetime dependent of the `LogManager`'s
            // lifetime due to `PhantomData`:
            _marker: PhantomData,
        }
    }
}

现在,Logger 的任何实例都不能比它的来源 LogManager 更长久。