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
更长久。
我在查看一些 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
更长久。