Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

特殊化の使用

特殊化は現在不安定です。その進捗はこちらで追跡できます。

私たちは特殊化に過度に依存することを避け、その使用を特定の実装の最適化に限定するようにしています。これらの特殊化された最適化では、公開メソッド自体を特殊化するのではなく、正しい実装を見つけるためにプライベートなトレイトを使用します。外部の呼び出し元に対するメソッドのディスパッチ方法を変更する特殊化の使用は、慎重に検討するべきです。

標準ライブラリで特殊化を使用する方法の例として、&[T] から Rc<[T]> を作成するケースを考えます。

impl<T: Clone> From<&[T]> for Rc<[T]> {
    #[inline]
    fn from(v: &[T]) -> Rc<[T]> {
        unsafe { Self::from_iter_exact(v.iter().cloned(), v.len()) }
    }
}

T: Copy の場合に最適化された実装があると便利です。

impl<T: Copy> From<&[T]> for Rc<[T]> {
    #[inline]
    fn from(v: &[T]) -> Rc<[T]> {
        unsafe { Self::copy_from_slice(v) }
    }
}

残念ながら、通常はこれら両方の impl を持つことはできません。重複してしまうためです。ここで、プライベートな特殊化を使用して内部的に正しい実装を選択できます。この場合、実装を切り替える RcFromSlice というトレイトを使用します。

impl<T: Clone> From<&[T]> for Rc<[T]> {
    #[inline]
    fn from(v: &[T]) -> Rc<[T]> {
        <Self as RcFromSlice<T>>::from_slice(v)
    }
}

/// `From<&[T]>` に使用される特殊化トレイト。
trait RcFromSlice<T> {
    fn from_slice(slice: &[T]) -> Self;
}

impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
    #[inline]
    default fn from_slice(v: &[T]) -> Self {
        unsafe { Self::from_iter_exact(v.iter().cloned(), v.len()) }
    }
}

impl<T: Copy> RcFromSlice<T> for Rc<[T]> {
    #[inline]
    fn from_slice(v: &[T]) -> Self {
        unsafe { Self::copy_from_slice(v) }
    }
}

min_specialization feature を使用した特殊化のみを使用するべきです。完全な specialization feature は不健全であることが知られています。

特殊化属性

デフォルト実装には現れないトレイト境界を、特殊化する実装で許可するために使用できる不安定な属性が 2 つあります。

rustc_specialization_trait は、トレイトの実装を「常に適用可能」なものに制限します。rustc_specialization_trait で注釈されたトレイトの実装は不安定なので、標準ライブラリからエクスポートされる stable なトレイトには使用するべきではありません。Sized は例外であり、すでに impl ブロックでは実装できないため、この属性を持つことができます。 : rustc_specialization_trait は誤ったモノモーフィゼーションを防ぐだけであり、型が特殊化された型と特殊化されていない型の間で強制変換されることを防ぎません。これは、特殊化を一貫して適用しなければならない場合に重要になることがあります。詳細については rust-lang/rust#85863 を参照してください。

rustc_unsafe_specialization_marker は、関連項目を持たないトレイトに基づく特殊化を許可します。この属性が unsafe であるのは、特殊化の際にトレイトの実装から得られるライフタイム制約が考慮されないためです。次の例は rustc_unsafe_specialization_marker の制限を示しています。特殊化された実装は、'static ライフタイムを持つものだけでなく、すべての共有参照型に対して使用されます。このため、rustc_unsafe_specialization_marker の新しい使用は避けるべきです。

#[rustc_unsafe_specialization_marker]
trait StaticRef {}

impl<T> StaticRef for &'static T {}

trait DoThing: Sized {
    fn do_thing(self);
}

impl<T> DoThing for T {
    default fn do_thing(self) {
        // 遅い実装
    }
}

impl<T: StaticRef> DoThing for T {
    fn do_thing(self) {
        // 高速な実装
    }
}

rustc_unsafe_specialization_marker は、CopyFusedIteratorEq など、std からエクスポートされるマーカートレイトに基づく既存の特殊化を許可するために存在します。