Struct core::marker::PhantomData [] [src]

pub struct PhantomData<T: ?Sized>;

PhantomData<T> allows you to describe that a type acts as if it stores a value of type T, even though it does not. This allows you to inform the compiler about certain safety properties of your code.

For a more in-depth explanation of how to use PhantomData<T>, please see the Nomicon.

A ghastly note 👻👻👻

Though they both have scary names, PhantomData<T> and 'phantom types' are related, but not identical. Phantom types are a more general concept that don't require PhantomData<T> to implement, but PhantomData<T> is the most common way to implement them in a correct manner.

Examples

Unused lifetime parameter

Perhaps the most common time that PhantomData is required is with a struct that has an unused lifetime parameter, typically as part of some unsafe code. For example, here is a struct Slice that has two pointers of type *const T, presumably pointing into an array somewhere:

fn main() { struct Slice<'a, T> { start: *const T, end: *const T, } }
struct Slice<'a, T> {
    start: *const T,
    end: *const T,
}

The intention is that the underlying data is only valid for the lifetime 'a, so Slice should not outlive 'a. However, this intent is not expressed in the code, since there are no uses of the lifetime 'a and hence it is not clear what data it applies to. We can correct this by telling the compiler to act as if the Slice struct contained a borrowed reference &'a T:

fn main() { use std::marker::PhantomData; #[allow(dead_code)] struct Slice<'a, T: 'a> { start: *const T, end: *const T, phantom: PhantomData<&'a T> } }
use std::marker::PhantomData;

struct Slice<'a, T: 'a> {
    start: *const T,
    end: *const T,
    phantom: PhantomData<&'a T>
}

This also in turn requires that we annotate T:'a, indicating that T is a type that can be borrowed for the lifetime 'a.

Unused type parameters

It sometimes happens that there are unused type parameters that indicate what type of data a struct is "tied" to, even though that data is not actually found in the struct itself. Here is an example where this arises when handling external resources over a foreign function interface. PhantomData<T> can prevent mismatches by enforcing types in the method implementations:

fn main() { #![allow(dead_code)] trait ResType { fn foo(&self); } struct ParamType; mod foreign_lib { pub fn new(_: usize) -> *mut () { 42 as *mut () } pub fn do_stuff(_: *mut (), _: usize) {} } fn convert_params(_: ParamType) -> usize { 42 } use std::marker::PhantomData; use std::mem; struct ExternalResource<R> { resource_handle: *mut (), resource_type: PhantomData<R>, } impl<R: ResType> ExternalResource<R> { fn new() -> ExternalResource<R> { let size_of_res = mem::size_of::<R>(); ExternalResource { resource_handle: foreign_lib::new(size_of_res), resource_type: PhantomData, } } fn do_stuff(&self, param: ParamType) { let foreign_params = convert_params(param); foreign_lib::do_stuff(self.resource_handle, foreign_params); } } }
use std::marker::PhantomData;
use std::mem;

struct ExternalResource<R> {
   resource_handle: *mut (),
   resource_type: PhantomData<R>,
}

impl<R: ResType> ExternalResource<R> {
    fn new() -> ExternalResource<R> {
        let size_of_res = mem::size_of::<R>();
        ExternalResource {
            resource_handle: foreign_lib::new(size_of_res),
            resource_type: PhantomData,
        }
    }

    fn do_stuff(&self, param: ParamType) {
        let foreign_params = convert_params(param);
        foreign_lib::do_stuff(self.resource_handle, foreign_params);
    }
}

Indicating ownership

Adding a field of type PhantomData<T> also indicates that your struct owns data of type T. This in turn implies that when your struct is dropped, it may in turn drop one or more instances of the type T, though that may not be apparent from the other structure of the type itself. This is commonly necessary if the structure is using a raw pointer like *mut T whose referent may be dropped when the type is dropped, as a *mut T is otherwise not treated as owned.

If your struct does not in fact own the data of type T, it is better to use a reference type, like PhantomData<&'a T> (ideally) or PhantomData<*const T> (if no lifetime applies), so as not to indicate ownership.

Trait Implementations

impl<T: ?Sized> Hash for PhantomData<T>

fn hash<H: Hasher>(&self, _: &mut H)

fn hash_slice<H: Hasher>(data: &[Self], state: &mut H) where Self: Sized

impl<T: ?Sized> PartialEq for PhantomData<T>

fn eq(&self, _other: &PhantomData<T>) -> bool

fn ne(&self, other: &Rhs) -> bool

impl<T: ?Sized> Eq for PhantomData<T>

fn assert_receiver_is_total_eq(&self)

impl<T: ?Sized> PartialOrd for PhantomData<T>

fn partial_cmp(&self, _other: &PhantomData<T>) -> Option<Ordering>

fn lt(&self, other: &Rhs) -> bool

fn le(&self, other: &Rhs) -> bool

fn gt(&self, other: &Rhs) -> bool

fn ge(&self, other: &Rhs) -> bool

impl<T: ?Sized> Ord for PhantomData<T>

fn cmp(&self, _other: &PhantomData<T>) -> Ordering

impl<T: ?Sized> Copy for PhantomData<T>

impl<T: ?Sized> Clone for PhantomData<T>

fn clone(&self) -> PhantomData<T>

fn clone_from(&mut self, source: &Self)

impl<T: ?Sized> Default for PhantomData<T>

fn default() -> PhantomData<T>

impl<T: ?Sized> Debug for PhantomData<T>

fn fmt(&self, f: &mut Formatter) -> Result