for ループで Vec を直接回すと要素がムーブされる
for x in vec のように所有権を持つVecを直接forに渡すと、内部でinto_iter()が呼ばれ各要素の所有権がムーブされます。ループの後で元のVecを使おうとするとE0382エラーになります。
エラーメッセージの読み方
error[E0382]: borrow of moved value: `names`
E0382- エラーコード — `rustc --explain E0382` で詳しい説明が見られます
borrow of moved value: `names`- 詳細メッセージ — 何が問題だったか
このエラーが出る典型パターン
パターン1
1 fn main() { 2 let names = vec![String::from("a"), String::from("b")]; 3 for name in names { ^ 4 println!("{}", name); 5 } 6 println!("{}", names.len()); 7 }
error[E0382]: borrow of moved value: `names`
forに所有権を持つVecを直接渡すと要素がムーブされます。ループ後も使いたい場合は&で参照を渡します。
直し方: names を &names にします。
広告
広告スロット(未設定)
パターン2
1 fn main() { 2 let words = vec![String::from("x"), String::from("y")]; 3 for w in words { ^ 4 println!("{}", w); 5 } 6 println!("{}", words.len()); 7 }
error[E0382]: borrow of moved value: `words`
所有権ごと消費するforループの後で元のVecを参照すると、E0382エラーになります。
直し方: words を &words にします。
パターン3
1 fn main() { 2 let items = vec![String::from("p"), String::from("q")]; 3 for it in items { ^ 4 println!("{}", it); 5 } 6 println!("{}", items.len()); 7 }
error[E0382]: borrow of moved value: `items`
&を付けて渡せば、要素を借用するだけでitemsの所有権は失われません。
直し方: items を &items にします。
パターン4
1 fn main() { 2 let labels = vec![String::from("m"), String::from("n")]; 3 for l in labels { ^ 4 println!("{}", l); 5 } 6 println!("{}", labels.len()); 7 }
error[E0382]: borrow of moved value: `labels`
参照付きのforは要素を&Stringとして借用するだけなので、ループの後もlabels自体は生きています。
直し方: labels を &labels にします。
パターン5
1 fn main() { 2 let tags = vec![String::from("s"), String::from("t")]; 3 for t in tags { ^ 4 println!("{}", t); 5 } 6 println!("{}", tags.len()); 7 }
error[E0382]: borrow of moved value: `tags`
要素を消費する必要が無いなら、常に&を付けて借用でループする方が安全です。
直し方: tags を &tags にします。
よくある誤解
「forループは要素を一時的に借りるだけで、元のコレクションは手つかずのまま残るはず」という思い込みは誤りです。&を付けずにforに渡すと所有権ごと消費されるため、ループ後に使いたい場合は&vecのように参照で渡す必要があります。
まとめ
for ループで Vec を直接回すと要素がムーブされるは中級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。