Copy / Clone トレイト
Copy
と Clone
の違い
Copy
複製は暗黙的に行われる。マーカートレイトの一つで、ビット列のコピーが行われる。Sallow copyとなるため、参照をうまく扱えない。Clone
複製は明示的に行う必要がある。clone
メソッドを実装することで、コピー内容を変更できる。ただしCopyトレイトを実装する場合は、*self
を返すようにする。大抵の場合においてdeep copy。
Note: StringはCloneトレイトではあるが、Copyトレイトではない
Stringは文字列バッファーへのポインターを持つ構成になっているため、単純なビット列コピーでは、多重開放される。 そのため、Copyトレイトではない。
Copyトレイト
Shallowコピーを行う。
役割
structをムーブセマンティクスからコピーセマンティクスに変更する。
struct Foo; let a = Foo; let b = a; take(a); // 所有権が存在しないのでエラー
#[derive(Copy, Clone)] struct Foo; let a = Foo; let b = a; take(a);
実装
マーカートレイトなのでderive
での実装が可能。またCloneのサブトレイトであるので、Cloneも指定する。
Cloneトレイト
役割
複製できるオブジェクトであることを表す。
実装
deriveでの実装が可能。ただしジェネリクスの際は、型パラメーターT
がCloneトレイトを実装していないと対象にならない。
#[derive(Clone)] struct Reading<T> { frequency: T, } struct NoCopy; fn main() { let a = Reading { frequency: NoCopy }; let b = a.clone(); } /* 10 | let b = a.clone(); | ^^^^^ method not found in `Reading<NoCopy>` */
フィールド項目にClone
トレイトが含まれていない場合は、手動で実装する必要がある。
この際、Copyトレイトも実装される際は、単純に *self
を返すようにする。
// 関数ポインターはCloneトレイトが実装されていないので、deriveが不可 struct Generate<T>(fn() -> T); // Copyはだたのマーカートレイト impl <T> Copy for Generate<T> {} impl <T> Clone for Generate<T> { fn clone(&self) -> Self { // Copyトレイトが実装されている場合は、単純に `*self` を返すようにする *self } }
まとめ
トレイトがシンタックスに大きな影響を与えるRustはメモリ管理を学ぶだけでは、コードは書けないということがよくわかりますね。