How can I initialize PhantomData fields?

Viewed 351

I'm trying to use the Type State Pattern to implement a server mock but am getting lost in the syntax. I have the following server code based on this tutorial for the Type State pattern:

/// Represents a PostgreSQL server.
pub struct Server<S: Messages> {
  marker: std::marker::PhantomData<S>,
  configuration: Configuration
}

/// Trait used to anchor message types.
pub trait Messages {}

/// Stopped server
pub enum Stopped {}
impl Messages for Stopped {}
impl Server<Stopped> {
  pub fn new(configuration: Configuration) -> Self {
    Server{configuration, marker: Stopped}
  }
}

/// Methods available to all messages
impl<S> Server<S> where S: Messages {}

Except I can't create the new method because I have no idea what to do about the marker property. Any ideas?

1 Answers

PhantomData implements Default, you can initialize it with:

Server {
    configuration,
    marker: Default::default(), 
    //marker: PhantomData::<Stopped> //or using explicit type 
    //marker: PhantomData // or sugar 
}

Since the marker field is not going to be used, you might want to define it as _marker: Default:default().


Trick that might help :

If you have multiple Sized generic parameters, you can use tuples instead of adding multiple marker fields:

pub struct Server<T, S, U, V> {
  _marker: std::marker::PhantomData<(T, S, U, V)>,
  configuration: Configuration
}

Note : Tuples only implement Default if there are 12 or less elements inside, but this is not a problem in here since internal defaults will not be called ever. (playground)

See also:

Related