I find the concept of PhantomData
in Rust quite confusing. I use it extensively to constrain object lifetimes in my FFI-based code, and I am still not sure whether I do it correctly or not.
Here's a contrived sample of how I often end up using it. For example, I do not want an instance of MyStruct
to outlive an instance of 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);
// ...
}
I don't quite understand the following:
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()
.For the purposes of lifetime tracking, does
PhantomData
even care about the actual type in the declaration ofmarker
? I tried changing it toPhantomData<&'a usize>
, and it still worked.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?Related to the previous question; if there are multiple input reference arguments with potentially different lifetimes, how does
PhantomData
determine which lifetime to use?
PhantomData
actually is, so I put them all in a single question – Roman Dmitrienko