Progrust Library.

// dictionary

Copyトレイト.

Copyは、値をビット単位で複製するだけで複製が成立することを示す、メソッドを1つも持たないトレイト(マーカートレイト)です1。Copyを実装した型は、代入や関数への受け渡しでムーブではなくコピーが起き、所有権は移らないため元の変数をそのまま使い続けられます。整数型や論理値型をはじめ、プリミティブ型の多くは最初からCopyを実装しています。

#[derive(Copy, Clone)]
struct Price {
    yen: u32,
}

fn main() {
    let regular = Price { yen: 1200 };
    let sale = regular; // ムーブではなくコピーが起きる

    println!("通常価格: {}円", regular.yen); // OK: regular はまだ使える
    println!("セール価格: {}円", sale.yen);
}
Playgroundで開く

実装できる型の条件

Copyはどんな型にも付けられるわけではなく、次の2つを両方満たす型だけが実装できます2。

条件 内容 違反時のエラー
全フィールドがCopy 構造体は全フィールド、列挙型は全バリアントの全フィールドがCopyである必要がある E0204
Dropを実装していない DropとCopyは同時に実装できない E0184

Dropを実装する型は自身のサイズを超えた資源(ヒープ領域など)を管理しているため、ビットの複製だけでは正しく増やせません1。文字列型やベクタ(Vec)がCopyになれないのはこのためです。

Cloneとの関係と使い分け

.clone()によるクローンを提供するCloneは、Copyのスーパートレイトです(pub trait Copy: Clone)。そのためCopyを実装する型は必ずCloneも実装する必要があり、derive属性では#[derive(Copy, Clone)]とセットで書くのが定型になっています1。

観点 Copy Clone
複製の起き方 代入・受け渡しで暗黙に .clone()で明示的に
複製の内容 ビット単位の複製に固定 型ごとに自由に実装できる
主な対象 ヒープを使わない小さな値 ヒープなどの資源を持つ型

小さくヒープを持たない型にはCopyを付けてコピーを気にせず扱えるようにし、資源を持つ型はCopyにできないので必要な場面だけ.clone()します。読み取りたいだけなら、どちらでもなく参照で借用するほうが安価です。

補足

条件を満たさない型に付けるとどうなるか

Copyでないフィールドを持つ型に付けるとE0204になります。

#[derive(Copy, Clone)] // エラー: E0204(Copyでないフィールドを含む)
struct Cart {
    items: Vec<String>, // Vec は Copy ではない
}

fn main() {
    let cart = Cart { items: vec![String::from("りんご")] };
    println!("商品数: {}", cart.items.len());
}
Playgroundで開く

Dropを実装している型に付けるとE0184になります。

#[derive(Copy, Clone)] // エラー: E0184(DropとCopyは同時に実装できない)
struct Receipt {
    id: u32,
}

impl Drop for Receipt {
    fn drop(&mut self) {
        println!("レシート{}を破棄しました", self.id);
    }
}

fn main() {
    let _receipt = Receipt { id: 1 };
}
Playgroundで開く
自動でCopyになる型と、参照の扱い

共有参照&Tは、TがCopyかどうかに関わらず常にCopyです1。一方で排他参照&mut TはCopyではありません(コピーできてしまうと、同じ値への排他参照が同時に複数存在することになるためです)。

このほか、Copyな型だけからなるタプル型や関数ポインタなど、自分でderiveしなくてもコンパイラがCopyを実装する型もあります2。

ムーブとコピーはどこが違うのか

実行時の動作としては、ムーブもコピーもメモリ上でビットが複製されることがあり(最適化で消えることもあります)、機械語のレベルでは同じ処理になり得ます。両者の本質的な違いは「複製したあとに元の値へアクセスしてよいかどうか」という、コンパイラが課す規則の側にあります1。

Footnotes

  1. std公式ドキュメント — Trait Copy ↩ ↩2 ↩3 ↩4 ↩5

  2. The Rust Reference — Special types and traits ↩ ↩2

この辞書が使われているページ

backlinks 8

  1. 辞書derive属性
  2. 辞書クローン
  3. 辞書トレイト
  4. 辞書ムーブ
  5. 辞書演算子オーバーロード
  6. 辞書構造体更新記法
  7. 辞書包括パターン
  8. 本動かして学ぶRustプログラミング問題集 › 第7章 所有権とムーブ