Use PhantomData<T> to inform the compiler about logical ownership or borrowing of type T for correct trait bounds and variance.
Use PhantomData<T> in a struct to tell the compiler that the type logically owns or borrows T, even if it holds no actual data of that type. This enforces correct variance, drop behavior, and trait bounds like Send or Sync.
use std::marker::PhantomData;
struct MyStruct<'a, T> {
// No actual field of type T, but we pretend we own one
_marker: PhantomData<&'a T>,
}
// Now MyStruct is not Send unless T is Send, and it borrows T
PhantomData is a zero-sized placeholder that tells the compiler your struct is connected to another type, even if it doesn't store it. It ensures the compiler enforces the same safety rules (like memory ownership or thread safety) as if the type were actually there. Think of it as a label on a box that says "contains fragile items" so handlers treat it carefully, even if the box is currently empty.