🖨️

RustのCopy & Cloneトレイト:違いを見分けられますか?

2025/03/02に公開

表紙

兄弟のような Copy と Clone

Rust において、CopyClone のトレイトは、型のコピーの挙動を制御するために使用されます。これらを使うことで、型の値をどのようにコピーするか、またどのような状況でコピーが可能かを定義できます。本記事では、この二つのトレイトの役割と使い方について詳しく説明し、コード例を交えてその使用方法を紹介します。

Copy トレイト

Copy トレイトは、型がビット単位でコピーできることを示します。このトレイトを実装した型は、代入、関数への引数渡し、戻り値として返す際に自動的にコピーされます。

Copy トレイトとは?

Copy トレイトはマーカー・トレイト(marker trait)であり、メソッドを一切持ちません。このトレイトは単に「この型はビット単位でコピー可能である」ことを示すためのものです。

#[derive(Copy)]
struct Point {
    x: i32,
    y: i32,
}

Copy トレイトの実装方法

Copy トレイトを実装するには、型の定義に #[derive(Copy)] 属性を追加する必要があります。さらに、Copy を実装する型は Clone も実装しなければならないため、#[derive(Clone)] も併せて指定します。

#[derive(Copy, Clone)]
struct Point {
    x: i32,
    y: i32,
}

もし Copy トレイトを実装しようとして Clone を実装しなかった場合、コンパイルエラーが発生します。例えば:

#[derive(Copy)]
struct Point {
    x: i32,
    y: i32,
}

// error[E0277]: the trait bound `Point: std::clone::Clone` is not satisfied

エラーメッセージが示す通り、Point 型が Clone トレイトを実装していないため、Copy を実装することができません。

これは、Copy を実装するすべての型が Clone も実装する必要があるためです。Rust では clone メソッドを明示的に呼び出す際、ユーザーがビット単位のコピーを意図していると判断されます。そのため、Copy トレイトを実装する場合、必ず Clone も実装しなければなりません。

Copy トレイトを実装できる型

すべての型が Copy を実装できるわけではありません。以下の条件を満たす型のみが Copy を実装できます。

  • 型自体が「POD(Plain Old Data)」型であること(つまり、ポインタや参照を含まないこと)。
  • その型のすべてのフィールドが Copy を実装していること。

例えば、以下の型は Copy を実装できません。なぜなら、参照フィールドを含んでいるためです。

struct Foo<'a> {
    x: &'a i32,
}

// error[E0204]: the trait `Copy` may not be implemented for this type
impl Copy for Foo<'_> {}

Copy トレイトが必要な理由

Copy トレイトを実装することで、型の値を代入や引数渡し、戻り値として返す際に明示的に clone を呼び出す必要がなくなります。

また、Copy 型の値は常にビット単位でコピーされるため、コピー処理のオーバーヘッドが少なくなります。これはプログラムのパフォーマンス向上に役立ちます。

Clone トレイト

Copy とは異なり、Clone トレイトは型の値を明示的にコピーすることを可能にします。このトレイトを実装した型は、clone メソッドを呼び出して新しいコピーを作成できます。

Clone トレイトとは?

Copy とは異なり、Clone は通常のトレイトであり、clone というメソッドを持っています。このメソッドは、新しいコピーを作成するために使用されます。

#[derive(Clone)]
struct Point {
    x: i32,
    y: i32,
}

Clone トレイトの実装方法

Clone トレイトを実装するには、#[derive(Clone)] を指定するか、clone メソッドを手動で実装する方法があります。

#[derive(Clone)]
struct Point {
    x: i32,
    y: i32,
}

// `clone` メソッドを手動実装する場合
impl Clone for Point {
    fn clone(&self) -> Self {
        Self { x: self.x, y: self.y }
    }
}

Clone トレイトを実装できる型

ほとんどすべての型は Clone を実装できます。新しいコピーを作成する方法さえ定義できれば、Clone を実装できます。

Clone トレイトが必要な理由

Clone トレイトを使うことで、明示的に型の値をコピーできます。これは、ポインタや参照を含む型など、ビット単位のコピーができない場合に特に有用です。

さらに、Clone トレイトを実装することで、コピーの際に特定の処理を追加できます。例えば、clone メソッド内でリソースの確保やカウンタの更新を行うことが可能です。

CopyClone の違いと関係

CopyClone の両方が型のコピーに関するトレイトですが、それぞれの役割には違いがあります。

  • Copy はマーカー・トレイトであり、型がビット単位でコピー可能であることを示します。このトレイトを実装すると、代入や関数の引数・戻り値として自動的にコピーされます。
  • Clone は通常のトレイトであり、clone メソッドを提供します。このメソッドを呼び出すことで、明示的に新しいコピーを作成できます。

さらに、Copy を実装するすべての型は Clone も実装しなければなりません。これは、明示的に clone を呼び出す際に、Rust がビット単位でコピーすることを保証するためです。

実例

以下に、CopyClone を使用したコード例を示します。

#[derive(Copy, Clone)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = p1; // 自動コピー
    let p3 = p1.clone(); // 明示的なコピー
}

この例では、Point 型を定義し、CopyClone を実装しました。main 関数内で Point の値を別の変数に代入すると、Copy により自動的にコピーされます。また、clone メソッドを呼び出すことで、明示的に新しいコピーを作成できます。


私たちはLeapcell、Rustプロジェクトのホスティングの最適解です。

Leapcell

Leapcellは、Webホスティング、非同期タスク、Redis向けの次世代サーバーレスプラットフォームです:

複数言語サポート

  • Node.js、Python、Go、Rustで開発できます。

無制限のプロジェクトデプロイ

  • 使用量に応じて料金を支払い、リクエストがなければ料金は発生しません。

比類のないコスト効率

  • 使用量に応じた支払い、アイドル時間は課金されません。
  • 例: $25で6.94Mリクエスト、平均応答時間60ms。

洗練された開発者体験

  • 直感的なUIで簡単に設定できます。
  • 完全自動化されたCI/CDパイプラインとGitOps統合。
  • 実行可能なインサイトのためのリアルタイムのメトリクスとログ。

簡単なスケーラビリティと高パフォーマンス

  • 高い同時実行性を容易に処理するためのオートスケーリング。
  • ゼロ運用オーバーヘッド — 構築に集中できます。

ドキュメントで詳細を確認!

Try Leapcell

Xでフォローする:@LeapcellHQ


ブログでこの記事を読む

Discussion