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パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。