サブタイプ化と変性
サブタイプ化は暗黙的で型のチェックや推論のどの段階でもおきうる。
サブタイプ化は二つの場合に限定される: ライフタイムにおける変性そして高階ライフタイムを伴う型どうしのものである。もし型からライフタイプを除けば、ただサブタイプ化は型が同じかにのみよるだろう。
以下の例について考えると: 文字列リテラルは常に
`static
ライフタイムを持つ。それでもなお、s
をt
へ代入できる。fn bar<'a>() { let s: &'static str = "hi"; let t: &'a str = s; }
'static
はライフタイムパラメタ'a
よりも長生きするため、&'static str
は&'a str
のサブタイプになる。変性
変性はジェネリクス型がその引数に関連して持つ性質である。ジェネリクス型のパラメタ中の変性は、そのパラメタのサブタイプ化がどのようにその型のサブタイプ化に影響するかという事である。
F<T>
がT
について共変の場合、もしT
がU
のサブタイプならF<T>
がF<U>
のサブタイプだと含意される (“素通り” サブタイプ)
F<T>
がT
について反変の場合、もしT
がU
のサブタイプならF<U>
がF<T>
のサブタイプだと含意される
F<T>
がT
について不変の場合、それら以外となる (サブタイプ化の関係は派生しない)型の変性は自動的に以下のように決定される
型 'a
での変性T
での変性&'a T
共変 共変 &'a mut T
共変 不変 *const T
共変 *mut T
不変 [T]
and[T; n]
共変 fn() -> T
共変 fn(T) -> ()
反変 std::cell::UnsafeCell<T>
不変 std::marker::PhantomData<T>
共変 dyn Trait<T> + 'a
共変 不変 その他
struct
,enum
, そしてunion
型はそれらのフィールドの型の変性を見て決定される。もしパラメタが位置によって異なる変性で使われていれば、そのパラメタは不変になる。例えば、以下の構造体は'a
とT
では共変で'b
,'c
, そしてU
では不変である。use std::cell::UnsafeCell; struct Variance<'a, 'b, 'c, T, U: 'a> { x: &'a U, // This makes `Variance` covariant in 'a, and would // make it covariant in U, but U is used later y: *const T, // Covariant in T z: UnsafeCell<&'b f64>, // Invariant in 'b w: *mut U, // Invariant in U, makes the whole struct invariant f: fn(&'c ()) -> &'c () // Both co- and contravariant, makes 'c invariant // in the struct. }
struct
,enum
, またはunion
の外で使われる時は、パラメタのその変性はそれぞれの位置ごとに分けて判定される。fn generic_tuple<'short, 'long: 'short>( // 'long is used inside of a tuple in both a co- and invariant position. x: (&'long u32, UnsafeCell<&'long u32>), ) { // As the variance at these positions is computed separately, // we can freely shrink 'long in the covariant position. let _: (&'short u32, UnsafeCell<&'long u32>) = x; } fn takes_fn_ptr<'short, 'middle: 'short>( // 'middle is used in both a co- and contravariant position. f: fn(&'middle ()) -> &'middle (), ) { // As the variance at these positions is computed separately, // we can freely shrink 'middle in the covariant position // and extend it in the contravariant position. let _: fn(&'static ()) -> &'short () = f; }