我发现Rust中PhantomData
的概念非常令人困惑。我在基于FFI的代码中广泛使用它来约束对象的生存期,但我仍然不确定我是否正确。
下面是一个我经常使用它的人为示例。例如,我不希望MyStruct
的实例比Context
:的实例更长寿
// FFI declarations and types
mod ffi {
use std::ffi::c_void;
pub type handle_t = *const c_void;
// ...
}
// A wrapper structure for some context created and maintained
// inside the C library
struct Context {
// ...
}
// Handle is only valid as long as the Context is alive.
// Hence, I use the PhantomData marker to constrain its lifetime.
struct MyStruct<'a> {
marker: PhantomData<&'a Context>,
handle: ffi::handle_t,
}
impl<'a> MyStruct<'a> {
fn new(context: &'a Context) -> Self {
let handle: ffi::handle_t = context.new_handle();
MyStruct {
marker: PhantomData,
handle
}
}
}
fn main() {
// Initialize the context somewhere inside the C library
let ctx = Context::new(unsafe {ffi::create_context()});
// Create an instance of MyStruct
let my_struct = MyStruct::new(&ctx);
// ...
}
我不太理解以下内容:
从语法上讲,
marker: PhantomData
到底是什么?我的意思是,它看起来不像构造函数,我希望它像PhantomData{}
或PhantomData()
。出于寿命跟踪的目的,
PhantomData
是否关心marker
声明中的实际类型?我试着把它改成PhantomData<&'a usize>
,它仍然有效。在我的
MyStruct::new()
方法的声明中,如果我忘记为context
参数显式指定'a
生存期,那么PhantomData
的魔力就会消失,在MyStruct
之前删除Context
就可以了。这是相当阴险的;编译器甚至不会发出警告。那么它给marker
分配了什么寿命,为什么?与上一个问题有关;如果有多个具有潜在不同生存期的输入引用参数,
PhantomData
如何确定使用哪个生存期?
marker: PhantomData
在语法上到底是什么?我的意思是,它看起来不像构造函数,我希望它像PhantomData{}
或PhantomData()
。
您可以定义一个零字段结构,如下所示:
struct Foo;
并创建一个这样的实例:
let foo: Foo = Foo;
类型和值都命名为Foo
。
为了跟踪生存期,
PhantomData
是否关心标记声明中的实际类型?我尝试将其更改为PhantomData<&'a usize>
,但它仍然有效。
PhantomData
没有什么特别之处,只是它的类型参数未使用不是一个错误(请参阅源代码(。此行为是通过#[lang = "phantom_data"]
属性启用的,它只是编译器中用于此目的的挂钩。
在我的
MyStruct::new()
方法的声明中,如果我忘记为context
参数显式指定'a
生存期,PhantomData
的魔力就会消失,在MyStruct
之前删除Context
就可以了。这是相当阴险的;编译器甚至不会发出警告。那么它给marker
分配了什么寿命,为什么?
PhantomData
可以让您告诉编译器信息,它无法推断自己,因为这些信息是关于您没有直接使用的类型的。这取决于你给编译器正确的信息。
在我的
MyStruct::new()
方法的声明中,如果我忘记为context
参数显式指定'a
生存期,那么PhantomData
的魔力就会消失,在MyStruct
之前删除Context
就可以了。这是相当阴险的;编译器甚至不会发出警告。那么marker
的寿命是多少,为什么?
我不完全确定我是否理解这个问题。PhantomData
不做任何事情——它只是一种向编译器传达您正在以某种方式使用数据的方式,由您准确地表达信息。请注意,即使您不正确地表达了约束,只有当您也有unsafe
代码时,才有可能引入内存不安全。在PhantomData
中正确表达生存期是围绕不安全代码创建安全抽象的一部分。