我正在浏览一些 rust 源代码,我发现了一个名为PhantomData
. 我正在浏览 rust 文档并在互联网上进行了很多搜索。但是,我无法理解这种数据类型与 rust 的实际用途。如果可能的话,有人可以用简单的方式解释一下吗?
pub struct GPIOD {
_marker: PhantomData<*const ()>,
}
我正在浏览一些 rust 源代码,我发现了一个名为PhantomData
. 我正在浏览 rust 文档并在互联网上进行了很多搜索。但是,我无法理解这种数据类型与 rust 的实际用途。如果可能的话,有人可以用简单的方式解释一下吗?
pub struct GPIOD {
_marker: PhantomData<*const ()>,
}
该PhantomData
结构旨在向编译器发出信号,表明正在以某种对编译器透明的方式使用类型或生命周期。
引用文档:
向你的类型添加一个 PhantomData 字段会告诉编译器你的类型表现得好像它存储了一个 type 的值
T
,即使它不是真的。在计算某些安全属性时使用此信息。
例如,如果我们查看 slice 的迭代器类型[T]
:std::slice::Iter<'a, T>
并使用src按钮声明它,我们将看到它实际上是这样声明的:
struct Iter<'a, T: 'a> {
start: *const T,
end: *const T,
_phantom: PhantomData<&'a T>,
}
std
频繁使用指针算术以使优化更容易获得(尽管这并不支持在用户代码中使用指针算术)。在这种情况下,我们需要确保两个原始指针(不携带生命周期)指向的数据比结构体的寿命更长,因此我们保留 aPhantomData<&'a T>
来告诉编译器表现得像Iter
拥有 a&'a T
因此强制执行生命周期规则为了它。
除了其他答案,我想添加一个示例。正如在另一个答案中所说,PhantomData
允许在 2 个结构之间添加任意寿命依赖性。
假设您有一个结构,它管理一个带有消息接收器的日志记录工具,以及一个表示将消息发送到管理器的实际记录器的结构。尽管记录器不直接依赖于管理器,但管理器必须比记录器活得更长,以防止发送错误。
天真的代码不会在 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
它的来源更长寿。