サブタイプ化と変性
サブタイプ化は暗黙的で型のチェックや推論のどの段階でもおきうる。
サブタイプ化は二つの場合に限定される: ライフタイムにおける変性そして高階ライフタイムを伴う型どうしのものである。もし型からライフタイプを除けば、ただサブタイプ化は型が同じかにのみよるだろう。
以下の例について考えると: 文字列リテラルは常に
'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; }