Copy型

ムーブセマンティクスがデフォルトですが、特定の型はデフォルトでコピーされます。

// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0

fn main() {
    let x = 42;
    let y = x;
    dbg!(x); // Copy でなければアクセスできない
    dbg!(y);
}

これらの型は Copy トレイトを実装しています。

自分で定義した型でも、コピーセマンティクスを使うようにオプトインできます。

// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0

#[derive(Copy, Clone, Debug)]
struct Point(i32, i32);

fn main() {
    let p1 = Point(3, 4);
    let p2 = p1;
    println!("p1: {p1:?}");
    println!("p2: {p2:?}");
}
  • 代入後、p1p2 はどちらもそれぞれのデータを所有します。
  • また、p1.clone() を使ってデータを明示的にコピーすることもできます。

コピーとクローンは同じものではありません。

  • コピーはメモリ領域のビット単位の複製を指し、任意のオブジェクトに対して機能するわけではありません。
  • コピーではカスタムロジックを入れられません(C++ のコピーコンストラクタとは異なります)。
  • クローンはより一般的な操作であり、Clone トレイトを実装することでカスタムな振る舞いも可能です。
  • コピーは Drop トレイトを実装している型では機能しません。

上の例で、次を試してください。

  • struct PointString フィールドを追加します。StringCopy 型ではないため、コンパイルできなくなります。
  • derive 属性から Copy を削除します。すると、コンパイラエラーは p1println! で発生します。
  • 代わりに p1 をクローンすると動作することを確認します。

さらに詳しく

  • 共有参照は Copy/Clone ですが、可変参照はそうではありません。これは、Rust が可変参照に排他性を要求するためです。したがって、共有参照のコピーを作るのは有効ですが、可変参照のコピーを作ると Rust の借用規則に違反します。