Using PhantomData to deal with unused type parameter


Consider the following trait, that is(as the name suggest) intended to represent types that contain a continuous sequence of T’s:

pub trait Array<T> {
	fn as_slice(&self) -> &[T];
	fn as_mut_slice(&mut self) -> &mut [T];

The best way I could come up with to make a struct that contains data of a type that implements this trait, while also being generic about the generic type T of the trait is:

struct Foo<T, A: Array<T>> {
	_marker: PhantomData<T>,
	data: A

Is there a better way? From what I’ve read about PhantomData, it’s intended to deal with situations where data is stored in a custom way(like with raw pointers), but in this case, all data is stored in a normal, safe-rust way.


If you intend for an impl to only impl Array for a single type, then you can use associated types:

trait Array { type Item; // rest of your functions }
struct Foo<T, A: Array<Item=T>> { a: A }


Hmm, that works, but then you can’t say that it has to implement another trait that requires the type T:

pub trait Array<T> : Deref<Target=[T]> {


Indeed, this won’t work (and saying : Deref<Target=[Self::Item]> creates circularity). See my subsequent reply.

So the original formulation you had was fine as well (and if you wanted a given type to impl Array for different Ts, the associated type formulation wouldn’t work either). PhantomData is used whenever generic types (or lifetime parameters) don’t appear in the fields of a struct; one case, albeit common, is when fields aren’t using the type directly. But another usage, a bit less common probably, is for type level concepts only (i.e. no runtime storage of it). Some examples of that are “session types” where a generic parameter captures the state of a type but otherwise has no “physical” representation. Another example is something like

So, I wouldn’t necessarily avoid PhantomData - it’s just a matter of whether you want to represent something only at the type level or not.


I take it back - you can say : Deref<Target=<Self as Array>::Item> and use the associated type. Although I must say I don’t quite get why this syntax works but not the Self::Item one.


Ok thanks! That was very insightfull, the type system can get very confusing at times. It just seemed like I was missing something, but I guess not.


Yeah, it can. In this case, it didn’t seem right that using an associated type should preclude using the generic (associated) type to require another generic trait to be implemented. I am, however, curious why Deref<Target=[Self::Item]> doesn’t work but Deref<Target=[<Self as Array>::Item]> does, as mentioned. If nobody replies here, I’ll try to follow up with a github issue and hopefully get someone to enlighten over there.


It’s been reported several times (and I’ve also personally ran into it multiple times :P)


Great, thanks!