Progrust Library.

// dictionary

ムーブ.

Rustでは以下のようにヒープに格納された値を持つ変数をほかの変数へコピーできます。このコピーではヒープメモリ上のデータは複製されません。

let order = String::from("コーヒー ×2");
let confirmed = order;

このコピーではその所有権も同時に渡されます。「所有者は常にただ1つ」というルールを保つため、所有権がない変数は無効となり、その後の利用はできなくなります。
そのため、このようなコピーをRustでは「ムーブ(move)」と呼びます。

fn main() {
    let order = String::from("コーヒー ×2");
    let confirmed = order; // 所有権が order から confirmed へムーブ

    println!("{confirmed}"); // OK: 今の所有者は confirmed
    println!("{order}"); // エラー: E0382(ムーブ済みの値の使用)
}
Playgroundで開く

ムーブが起きる場面

ムーブを起こすための特別な操作は基本的に不要で、値の受け渡しの際に自動で発生します。

場面 所有権の移動先
変数への代入 let b = a; b
関数の引数への受け渡し f(a) 関数の仮引数
関数からの戻り値 let b = f(); 受け取る側の変数 b

ムーブしない型(Copy型)

整数型論理値型のようなスカラー型などはCopyトレイトを実装しており、代入や受け渡しのたびに値そのものがコピーされるため、ムーブは起きません(移動元の変数もそのまま使えます)。一方、文字列型ベクタ(Vec)のようにヒープ領域の解放という後始末を担う型はCopyを実装できないため、ムーブが起きます。

補足

ムーブの実体は浅いコピー

文字列型をムーブしても、ヒープ上の文字列データ本体はコピーされません。移動するのはスタック上の管理情報(ヒープへのポインタ・長さ・容量)だけで、そのうえで移動元の変数が無効化されます。The Rust Referenceでは、ローカル変数からムーブした後のその場所は「未初期化(deinitialized)」となり、再代入で初期化し直すまで読み取れないと規定されています1。移動元を無効化することで、同じヒープ領域を2つの変数が指し続けること(二重解放の原因)を防いでいます。

ムーブさせずに値を使いたい場合

所有権を渡したくない場合は、参照で値を「借りる」(借用)のが基本です。また、独立した複製が必要なら.clone()によってクローンすることでヒープのデータごとコピーできます(そのぶん実行時コストがかかります)。

Footnotes

  1. The Rust Reference — Moved and copied types

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

backlinks 8

  1. 辞書クローン
  2. 辞書構造体更新記法
  3. 辞書参照
  4. 辞書所有権
  5. 辞書包括パターン
  6. 動かして学ぶRustプログラミング問題集 › 第10章 メソッドと関連関数
  7. 動かして学ぶRustプログラミング問題集 › 第7章 所有権とムーブ
  8. 動かして学ぶRustプログラミング問題集 › 第9章 構造体