Menu
Coddy logo textTech

Clone と Copy

CoddyのRustジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 37/61。

Rustでは、値をanother変数に代入すると、通常は所有権が移動し、元の変数は無効になります。ただし、2つの標準トレイト、CloneCopyによって、この動作は変わります。

Copy トレイトは暗黙的なビット単位のコピーを可能にします。型が Copy を実装すると、それを another 変数に assigning することで、所有権を移動する代わりに自動的なコピーが作成されます。

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

let p1 = Point { x: 10, y: 20 };
let p2 = p1;  // p1 はコピーされ、ムーブされない

println!("{}, {}", p1.x, p2.x);  // 両方とも有効です!

Cloneトレイトは、explicit なディープコピー.clone()メソッドによって提供します。Copyをderiveする場合は必須ですが、明示的なコピーが必要な型では単独で使用することもできます。

let p3 = p1.clone();  // 明示的なコピー

重要な制限があります。すべてのフィールドも Copy を implement している型に対してのみ、Copy を derive できます。整数や浮動小数点数のような単純な型は Copy ですが、String はそうではありません。String はヒープメモリを管理します。構造体に String が含まれている場合、derive できるのは Clone だけで、Copy は derive できません。

Trait動作用途
Copy暗黙的、自動スタックのみの単純なデータ
Clone.clone() による明示的な複製複製可能な任意のデータ

プリミティブ型のフィールドを持つ単純な構造体では、両方のトレイトを導出すると、所有権を気にせずに値を自由に代入できます。

challenge icon

チャレンジ

簡単

CopyClone トレイトの違いを示す座標系を作成しましょう!暗黙的にコピーできる構造体と、明示的なクローンが必要な構造体を 1 つずつ作成し、derive するトレイトによって Rust が複製を異なる方法で処理する様子を確認します。

コードを 2 つのファイルに分けて整理します。

  • coordinates.rs: 異なる種類の座標を表す 2 つの公開構造体を Define します。
    • GridPoint: 公開 x および y fields(どちらも i32)を持ちます。プリミティブ型のみを含むため、CopyClone の両方を derive し、代入時に暗黙的にコピーできるようにします。
    • NamedLocation: 公開 name(String)と x/y fields(i32)を持ちます。String を含むため、derive できるのは Clone だけで、Copy は derive できません。この構造体を複製するには、明示的な .clone() 呼び出しが必要です。
  • main.rs: coordinates モジュールを取り込み、各構造体が複製時にどのように異なる動作をするかを示します。提供された入力を使用してインスタンスを作成し、次に以下を示します。
    • GridPoint は another 変数に代入でき、両方とも有効なままになる(暗黙的なコピー)
    • NamedLocation は、元の値を有効なままにして duplicate を作成するために .clone() を使用する必要がある

複製後に両方の変数が有効であることを証明するため、元の値とコピー/クローンされた値の両方を出力します。

Original point: ({x}, {y})
Copied point: ({x}, {y})
Original location: {name} at ({x}, {y})
Cloned location: {name} at ({x}, {y})

たとえば、入力が 510Home の場合:

Original point: (5, 10)
Copied point: (5, 10)
Original location: Home at (5, 10)
Cloned location: Home at (5, 10)

3 つの入力を受け取ります。x 座標(i32 として parse)、y 座標(i32 として parse)、および location name です。

REQUIRED OUTPUT FORMAT: [Your translated content here]

自分で試してみよう

mod coordinates;

use coordinates::{GridPoint, NamedLocation};

fn main() {
    // 入力を読み取る
    let mut input1 = String::new();
    std::io::stdin().read_line(&mut input1).expect("Failed to read line");
    let x: i32 = input1.trim().parse().expect("Invalid number");

    let mut input2 = String::new();
    std::io::stdin().read_line(&mut input2).expect("Failed to read line");
    let y: i32 = input2.trim().parse().expect("Invalid number");

    let mut input3 = String::new();
    std::io::stdin().read_line(&mut input3).expect("Failed to read line");
    let name = input3.trim().to_string();

    // TODO: x と y で GridPoint のインスタンスを作成する

    // TODO: 別の変数に代入して暗黙的なコピーを示す
    // (GridPoint は Copy を実装しているため、これは自動的にコピーを作成します)

    // TODO: 元のポイントとコピーしたポイントを出力する
    // Format: "Original point: ({x}, {y})"
    // 形式: "Copied point: ({x}, {y})"

    // TODO: name、x、y で NamedLocation のインスタンスを作成する

    // TODO: 明示的なクローンを示す(NamedLocation は Clone のみを実装し、Copy は実装していない)
    // .clone() を使用して複製を作成する

    // TODO: Print original and cloned location
    // Format: "Original location: {name} at ({x}, {y})"
    // Format: "Cloned location: {name} at ({x}, {y})"
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Rustオンラインコンパイラ