Code Fix

初級

E0382: borrow of moved value(ムーブ後の値の使用)の原因と直し方

StringやVecのようにCopyトレイトを実装しない値を別の変数に代入すると、所有権が移動(ムーブ)します。ムーブ後に元の変数を使おうとすると、コンパイル時にE0382エラーになります。

エラーメッセージの読み方

error[E0382]: borrow of moved value: `s1`
E0382
エラーコード — `rustc --explain E0382` で詳しい説明が見られます
borrow of moved value: `s1`
詳細メッセージ — 何が問題だったか

このエラーが出る典型パターン

パターン1

 1  fn main() {
 2      let s1 = String::from("hello");
 3      let s2 = s1           ;
                       ^
 4      println!("{} {}", s1, s2);
 5  }
error[E0382]: borrow of moved value: `s1`

s1をそのままs2に代入すると所有権が移動し、s1は無効になります。両方使いたい場合はcloneで複製します。

直し方: s1 を s1.clone() にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  fn main() {
 2      let name1 = String::from("taro");
 3      let name2 = name1           ;
                            ^
 4      println!("{} {}", name1, name2);
 5  }
error[E0382]: borrow of moved value: `name1`

Stringのようにヒープにデータを持つ型は、代入すると値がコピーされず所有権だけが移動します。

直し方: name1 を name1.clone() にします。

この問題を解いてみる →

パターン3

 1  fn main() {
 2      let title = String::from("report");
 3      let copy = title           ;
                           ^
 4      println!("{} {}", title, copy);
 5  }
error[E0382]: borrow of moved value: `title`

整数のようなCopy型と違い、Stringは代入のたびに所有権の移動が起こります。

直し方: title を title.clone() にします。

この問題を解いてみる →

パターン4

 1  fn main() {
 2      let label = String::from("final");
 3      let backup = label           ;
                             ^
 4      println!("{} {}", label, backup);
 5  }
error[E0382]: borrow of moved value: `label`

ムーブ後に元の変数を使おうとすると、コンパイラがその場でE0382エラーとして検出します。

直し方: label を label.clone() にします。

この問題を解いてみる →

パターン5

 1  fn main() {
 2      let word = String::from("guide");
 3      let alt = word           ;
                         ^
 4      println!("{} {}", word, alt);
 5  }
error[E0382]: borrow of moved value: `word`

両方の変数を独立して使いたい場合は、複製のコストと引き換えにcloneを使う必要があります。

直し方: word を word.clone() にします。

この問題を解いてみる →

よくある誤解

「代入は値のコピーだから、元の変数もそのまま使えるはず」という思い込みは誤りです。Copyを実装しない型の代入は所有権の移動であり、元の変数はその時点で無効になります。

実務での勘所

この制約は、CやC++で問題になるdouble free(同じメモリを2回解放してしまうバグ)を、安全なRustのコードでは構造的に起こりえなくするための仕組みです。もし代入後も両方の変数が同じヒープ上のデータの所有者だと思い込んでいたら、両方がスコープを抜けるときにそれぞれdropが呼ばれ、同じメモリを2回解放しようとしてしまいます。代入のたびに所有権を移動させ、元の変数を無効化することで、「そのデータの持ち主は常にちょうど1つ」という状態を型システムで保証し、二重解放が原理的に起きないようにしています。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)