コレクションはスマートポインターである
説明
Deref トレイトを使用して、
コレクションをスマートポインターのように扱い、データに対する所有ビューと借用ビューを提供します。
例
use std::ops::Deref;
struct Vec<T> {
data: RawVec<T>,
//..
}
impl<T> Deref for Vec<T> {
type Target = [T];
fn deref(&self) -> &[T] {
//..
}
}
Vec<T> は T を所有するコレクションである一方、スライス(&[T])は T の借用された
コレクションです。Vec に対して Deref を実装すると、&Vec<T> から &[T] への暗黙的な参照外しが可能になり、
自動参照外しの探索にその関係が含まれます。Vec に実装されていると期待されるほとんどのメソッドは、実際には
スライスに対して実装されています。
また、String と &str にも同様の関係があります。
動機
所有権と借用は Rust 言語の重要な側面です。データ構造は、良いユーザー体験を提供するために、 これらのセマンティクスを適切に考慮しなければなりません。データを所有するデータ構造を実装する場合、 そのデータの借用ビューを提供することで、より柔軟な API が可能になります。
利点
ほとんどのメソッドは借用ビューに対してのみ実装でき、その後、それらは所有ビューでも 暗黙的に利用可能になります。
クライアントに、データを借用するか所有権を取得するかの選択肢を与えます。
欠点
参照外しを介してのみ利用できるメソッドやトレイトは、境界チェック時に考慮されないため、
このパターンを使用するデータ構造でのジェネリックプログラミングは複雑になる可能性があります
(Borrow や AsRef トレイトなどを参照してください)。
議論
スマートポインターとコレクションは類似しています。スマートポインターは単一の オブジェクトを指すのに対し、コレクションは多数のオブジェクトを指します。型システムの観点から見ると、 両者の違いはほとんどありません。各データにアクセスする唯一の方法がコレクションを介することであり、 かつコレクションがデータの削除に責任を持つ場合、そのコレクションはデータを所有しています(共有所有権の場合であっても、 何らかの借用ビューが適切な場合があります)。コレクションがデータを所有している場合、 複数回参照できるように、そのデータの借用ビューを提供することは通常有用です。
ほとんどのスマートポインター(例: Foo<T>)は Deref<Target=T> を実装します。しかし、
コレクションは通常、カスタム型へ参照外しされます。[T] と str にはある程度の
言語サポートがありますが、一般的なケースでは、これは必須ではありません。Foo<T> は、
Bar が動的サイズ型であり、&Bar<T> が Foo<T> 内のデータの借用ビューである場合に、
Deref<Target=Bar<T>> を実装できます。
一般に、順序付きコレクションはスライス構文を提供するために、Range に対して Index を実装します。
ターゲットは借用ビューになります。