RustでPhantomDataにT以外のものを入れるのはなぜか

PhantomDataにT以外のものを入れるのは、主に3つの理由がある。

  • 生存期間変数に言及するため。
  • 変性を制御するため。
  • 所有関係を制御するため。

生存期間変数に言及するため

型だけではなく、生存期間変数も、迷子になっては困る。こういうときは参照を使って PhantomData<&'a T> のように書くことが多い。

変性を制御するため

PhantomData<T>T に対して共変である。つまり、 T より広い型 S があったとき(これは通常、生存期間変数を入れ替えることで発生する)、 PhantomData<S>PhantomData<T> より広いとみなされる。

現在のRustは、内部的には非変・共変・反変・双変の4つの変性を持つ。反変が今後も残るかはわからないが、非変と共変のどちらをとるかは場合による。

非変にするときはよく PhantomData<fn(T) -> T> と書く。

所有関係を制御するため

Drop Checkの関係で、「ある型がある型を(直接的に/間接的に)所有しているか」というのがborrow checkerの挙動に影響を与えてしまう。

この所有判定において、 PhantomData<T>T を所有しているとみなされる。所有していないとみなしたい場合は PhantomData<*const T>PhantomData<&'a T> を使うことが多い。

まとめ

PhantomDataは単に型や生存期間変数を迷子にしないという以上に、変性と所有関係という2つの隠し属性の制御にも用いられる。これらのためのイディオムがいくつか知られている。