トレイトが dyn 互換かどうかをマークする方法について。

背景

トレイトが dyn 互換かどうかは重要である。しかし、Rust の文法はこれをトレイト全体の内容から判断する。トレイトに何かマークをつけるようなスタイルではない。そのため、コードリーディング時に瞬間的な判断ができない。また、メソッドの追加や削除で思いがけず dyn 互換かどうかまでもを変更してしまうかもしれない。

このような心配は dyn 互換かどうかを明示的にマークできれば不要になる。

対策

dyn 互換

dyn 型の実装』が dyn 互換の型にしか使えないのを利用する。

サンプル


pub trait MyTrait {
    fn some_method(&self);
}

impl dyn MyTrait {}

dyn 非互換

dyn 非互換のマーカートレイトを基底にする。そして、マーカートレイトに dyn 非互換にするダミーメソッドを入れておく。このダミーメソッドは呼ばれても問題ないが、絶対に呼ばれたくないなら『Voldemort パターン - トレイトメソッドの仮想的な非公開化』も使える。

サンプル


pub trait MyTrait: NotDyn {
    fn some_method(&self);
}

pub trait NotDyn {
    #[doc(hidden)]
    fn __do_not_call() {}
}

impl<T: ?Sized> NotDyn for T {}

クレート紹介

dyn_compatible

ここで紹介した方法をトレイトへの属性マクロで実現するクレート。

トレイトに #[dyn_compatible(true)] のように指定するだけで機能する。