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); }