PhantomData 在 Rust 中究竟是如何工作的?
How exactly does PhantomData work in Rust?
我发现 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
生命周期,[=11 的魔法=] 消失,可以在 MyStruct
之前删除 Context
。这是相当阴险的;编译器甚至不发出警告。那么它分配给 marker
的生命周期是多少,为什么?
与上一个问题相关;如果有多个可能具有不同生命周期的输入引用参数,PhantomData
如何确定使用哪个生命周期?
What exactly is this marker: PhantomData
thing, syntactically? I mean, it does not look like a constructor, which I'd expect to be something like PhantomData{}
or PhantomData()
.
您可以定义一个零字段结构,如下所示:
struct Foo;
并像这样创建一个实例:
let foo: Foo = Foo;
类型和值都命名为Foo
。
For the purposes of lifetime tracking, does PhantomData
even care about the actual type in the declaration of marker? I tried changing it to PhantomData<&'a usize>
, and it still worked.
PhantomData
没有什么特别之处,只是它的类型参数未被使用不是错误(参见 the source)。此行为是通过 #[lang = "phantom_data"]
属性启用的,它只是编译器中为此目的的一个挂钩。
In the declaration of my MyStruct::new()
method, if I forget to explicitly specify the 'a
lifetime for the context
argument, the magic of PhantomData
disappears, and it becomes OK to drop Context
before MyStruct
. This is quite insidious; the compiler does not even give a warning. What lifetime does it assign to marker
then, and why?
PhantomData
是为了让你告诉编译器它不能推断自己的信息,因为这个信息是关于你没有直接使用的类型的。给编译器正确的信息取决于你。
In the declaration of my MyStruct::new()
method, if I forget to explicitly specify the 'a
lifetime for the context
argument, the magic of PhantomData
disappears, and it becomes OK to drop Context
before MyStruct
. This is quite insidious; the compiler does not even give a warning. What lifetime does it assign to marker
then, and why?
我不太确定我是否理解这个问题。 PhantomData
不会 做 任何事情 - 它只是一种与编译器沟通的方式,表明您正在以某种方式使用数据,您可以准确地表达该信息。请注意,即使您错误地表达了约束,也只有在您也有 unsafe
代码的情况下才可能引入内存不安全。在 PhantomData
中正确表达生命周期是围绕不安全代码创建安全抽象的一部分。
我发现 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
生命周期,[=11 的魔法=] 消失,可以在MyStruct
之前删除Context
。这是相当阴险的;编译器甚至不发出警告。那么它分配给marker
的生命周期是多少,为什么?与上一个问题相关;如果有多个可能具有不同生命周期的输入引用参数,
PhantomData
如何确定使用哪个生命周期?
What exactly is this
marker: PhantomData
thing, syntactically? I mean, it does not look like a constructor, which I'd expect to be something likePhantomData{}
orPhantomData()
.
您可以定义一个零字段结构,如下所示:
struct Foo;
并像这样创建一个实例:
let foo: Foo = Foo;
类型和值都命名为Foo
。
For the purposes of lifetime tracking, does
PhantomData
even care about the actual type in the declaration of marker? I tried changing it toPhantomData<&'a usize>
, and it still worked.
PhantomData
没有什么特别之处,只是它的类型参数未被使用不是错误(参见 the source)。此行为是通过 #[lang = "phantom_data"]
属性启用的,它只是编译器中为此目的的一个挂钩。
In the declaration of my
MyStruct::new()
method, if I forget to explicitly specify the'a
lifetime for thecontext
argument, the magic ofPhantomData
disappears, and it becomes OK to dropContext
beforeMyStruct
. This is quite insidious; the compiler does not even give a warning. What lifetime does it assign tomarker
then, and why?
PhantomData
是为了让你告诉编译器它不能推断自己的信息,因为这个信息是关于你没有直接使用的类型的。给编译器正确的信息取决于你。
In the declaration of my
MyStruct::new()
method, if I forget to explicitly specify the'a
lifetime for thecontext
argument, the magic ofPhantomData
disappears, and it becomes OK to dropContext
beforeMyStruct
. This is quite insidious; the compiler does not even give a warning. What lifetime does it assign tomarker
then, and why?
我不太确定我是否理解这个问题。 PhantomData
不会 做 任何事情 - 它只是一种与编译器沟通的方式,表明您正在以某种方式使用数据,您可以准确地表达该信息。请注意,即使您错误地表达了约束,也只有在您也有 unsafe
代码的情况下才可能引入内存不安全。在 PhantomData
中正确表达生命周期是围绕不安全代码创建安全抽象的一部分。