サブタイプ化と変性

サブタイプ化は暗黙的で型のチェックや推論のどの段階でもおきうる。

サブタイプ化は二つの場合に限定される: ライフタイムにおける変性そして高階ライフタイムを伴う型どうしのものである。もし型からライフタイプを除けば、ただサブタイプ化は型が同じかにのみよるだろう。

以下の例について考えると: 文字列リテラルは常に `static ライフタイムを持つ。それでもなお、st へ代入できる。

fn bar<'a>() {
    let s: &'static str = "hi";
    let t: &'a str = s;
}

'static はライフタイムパラメタ 'a よりも長生きするため、&'static str&'a str のサブタイプになる。

変性

変性はジェネリクス型がその引数に関連して持つ性質である。ジェネリクス型のパラメタ中の変性は、そのパラメタのサブタイプ化がどのようにその型のサブタイプ化に影響するかという事である。

型の変性は自動的に以下のように決定される

'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 型はそれらのフィールドの型の変性を見て決定される。もしパラメタが位置によって異なる変性で使われていれば、そのパラメタは不変になる。例えば、以下の構造体は 'aT では共変で '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;
}