Code Fix

中級

move クロージャに取り込んだ値をクロージャの外で使うと E0382 になる

moveを付けたクロージャは、参照する変数の所有権を丸ごと取り込みます。取り込まれた後にクロージャの外側でその変数を使おうとするとE0382エラーになります。

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

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

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

パターン1

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

moveを付けたクロージャは変数の所有権ごと取り込みます。外でも使いたいならmoveを外し借用させます。

直し方: move(空) にします。

この問題を解いてみる →

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

パターン2

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

moveクロージャに取り込まれた変数は、その時点で所有権がクロージャ側に移ってしまいます。

直し方: move(空) にします。

この問題を解いてみる →

パターン3

 1  fn main() {
 2      let city = String::from("osaka");
 3      let show_city = move     || println!("city: {}", city);
                            ^
 4      show_city();
 5      println!("{}", city);
 6  }
error[E0382]: borrow of moved value: `city`

クロージャの外側でも変数を使い続けたい場合は、参照として借用させるだけで十分な場合が多いです。

直し方: move(空) にします。

この問題を解いてみる →

パターン4

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

moveは主にスレッドなど、クロージャが元のスコープより長く生きる場面で必要になります。

直し方: move(空) にします。

この問題を解いてみる →

パターン5

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

この例のようにクロージャがすぐ実行されて終わる場合は、moveを付ける必要はありません。

直し方: move(空) にします。

この問題を解いてみる →

よくある誤解

「moveクロージャも、値を使うときだけ一時的に借りているだけのはず」という思い込みは誤りです。moveは名前の通り所有権そのものをクロージャの中に移動させるため、外側の変数はその時点で無効になります。

まとめ

move クロージャに取り込んだ値をクロージャの外で使うと E0382 になるは中級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

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