Code Fix

中級

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ループがinto_iter()を呼ぶというのは、Vecだけの特別な規則ではなく、for x in 対象という構文がIntoIteratorというトレイトを実装しているものなら何にでも一律に適用される、糖衣構文だからです。Vec<T>自身がIntoIteratorを実装するとT型の要素を消費しながら生成し、&Vec<T>(参照)も別途IntoIteratorを実装していて、こちらは&T型の要素を借用するだけで生成します。for x in &vecと書くと後者の実装が使われるため所有権が移動しない、という仕組みです。

演習をはじめる

関連するエラー

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