Rust中PhantomData类型的用法

4

我正在查看一些Rust源代码,发现了一个叫做 PhantomData 的数据类型。我翻阅了 Rust 文档并通过互联网进行了搜索,但是我无法理解这个数据类型在 Rust 中的实际用途。如果可能的话,请有经验的人给我简单地解释一下。

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

这是使用 svd2rust 自动生成的 HAL crate 吗? - Sébastien Renauld
是的,没错。 - hEShaN
2个回答

8

PhantomData结构体用于向编译器表明类型或生命周期被以对编译器透明的方式使用。

引用文档:

在类型中添加PhantomData字段,告诉编译器您的类型表现得像存储了类型T的值一样,即使实际上并没有。这些信息在计算某些安全性属性时使用。

例如,如果我们查看切片[T]的迭代器类型:std::slice::Iter<'a, T>使用src按钮进行声明,我们会发现它实际上是这样声明的:

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

std 经常使用指针算术以便更容易地进行优化 (虽然这并不是为了支持在用户代码中使用指针算术)。在这种情况下,我们需要确保被这两个裸指针(不带有生命周期)所指向的数据比结构体的生命周期更长,因此我们保留一个PhantomData<&'a T>,告诉编译器像 Iter 拥有一个 &'a T 一样,从而强制执行其生命周期规则。


5
除了其他回答之外,我想再举一个例子。如同其他回答所说,PhantomData 允许在两个结构体之间添加任意的生命周期依赖关系。
假设您有一个管理带有消息接收器日志工具的结构体和一个表示实际日志记录器发送消息到该管理器的结构体。虽然记录器不直接依赖于管理器,但管理器必须比记录器更长寿以防止发送错误。
简单的代码不会创建任何两个结构体之间的依赖关系:
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 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

我在codereview上编写了一个示例代码。 - Boiethios

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接