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つの隠し属性の制御にも用いられる。これらのためのイディオムがいくつか知られている。