Copy / Clone トレイト

CopyClone の違い

  • 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はメモリ管理を学ぶだけでは、コードは書けないということがよくわかりますね。

参照

Rust - RustのCloneとCopyについての素朴な疑問|teratail