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

Clone と Copy

リソースを扱う場合、デフォルトの動作では、代入や関数呼び出しの際に リソースが転送されます。しかし、場合によってはリソースの コピーも作成する必要があります。

Clone トレイトは、まさにこれを行うために役立ちます。最も一般的には、 Clone トレイトで定義されている .clone() メソッドを使用できます。

Copy: 暗黙的なクローン

Copy トレイトにより、追加のロジックを必要とせず、単にビットをコピーするだけで 型を複製できます。型が Copy を実装している場合、代入や関数呼び出しでは、 値をムーブする代わりに暗黙的にコピーします。

重要: Copy には Clone が必要です。Copy を実装する型はすべて、 Clone も実装しなければなりません。これは、Copy がサブトレイトとして定義されているためです: trait Copy: Clone {}Copy 型に対する Clone 実装は、単に ビットをコピーします。

すべての型が Copy を実装できるわけではありません。型が Copy になれるのは、次の場合のみです:

  • そのすべての構成要素が Copy である
  • 外部リソース(ヒープメモリ、ファイルハンドルなど)を管理しない
// リソースを持たないユニット構造体
// 注: Copy には Clone が必要なので、両方を derive する必要がある
#[derive(Debug, Clone, Copy)]
struct Unit;

// `Clone` トレイトを実装する、リソースを持つタプル構造体
// Box<T> は Copy ではないため、これは Copy にはなれない
#[derive(Clone, Debug)]
struct Pair(Box<i32>, Box<i32>);

fn main() {
    // `Unit` をインスタンス化する
    let unit = Unit;
    // `Unit` をコピーする - これはムーブではなく暗黙的なコピー!
    // Unit は Copy を実装しているため、値は自動的に複製される
    let copied_unit = unit;

    // 両方の `Unit` を独立して使用できる
    println!("original: {:?}", unit);
    println!("copy: {:?}", copied_unit);

    // `Pair` をインスタンス化する
    let pair = Pair(Box::new(1), Box::new(2));
    println!("original: {:?}", pair);

    // `pair` を `moved_pair` にムーブし、リソースを移動する
    // Pair は Copy を実装していないため、これはムーブである
    let moved_pair = pair;
    println!("moved: {:?}", moved_pair);

    // エラー!`pair` はリソースを失っている
    //println!("original: {:?}", pair);
    // TODO ^ この行のコメント解除を試してみてください

    // `moved_pair` を `cloned_pair` にクローンする(リソースも含まれる)
    // Copy とは異なり、Clone は明示的である - .clone() を呼び出す必要がある
    let cloned_pair = moved_pair.clone();
    // std::mem::drop を使用して、ムーブされた元のペアをドロップする
    drop(moved_pair);

    // エラー!`moved_pair` はドロップされている
    //println!("moved and dropped: {:?}", moved_pair);
    // TODO ^ この行のコメント解除を試してみてください

    // .clone() の結果は引き続き使用できる!
    println!("clone: {:?}", cloned_pair);
}