Code Fix

上級

ジェネリック関数に値を渡すと所有権がムーブされ2回使えない

ジェネリック型Tを所有権ごと受け取る関数に値を渡すと、Copyを実装していない型の場合は所有権がムーブされます。同じ値をもう一度渡そうとするとE0382エラーになります。

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

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

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

パターン1

 1  fn consume<T>(items: Vec<T>) -> usize {
 2      items.len()
 3  }
 4  fn main() {
 5      let data = vec![1, 2, 3];
 6      let a = consume(data         );
                              ^
 7      let b = consume(data);
 8      println!("{} {}", a, b);
 9  }
error[E0382]: use of moved value: `data`

consumeはVec<T>を所有権ごと受け取ります。dataを2回渡したいならcloneで複製する必要があります。

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

この問題を解いてみる →

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

パターン2

 1  fn process<T>(items: Vec<T>) -> usize {
 2      items.len()
 3  }
 4  fn main() {
 5      let list = vec!["a", "b"];
 6      let a = process(list         );
                              ^
 7      let b = process(list);
 8      println!("{} {}", a, b);
 9  }
error[E0382]: use of moved value: `list`

ジェネリック関数でも、Copyを実装しない型を値渡しすれば通常の所有権ムーブと同じことが起こります。

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

この問題を解いてみる →

パターン3

 1  fn handle<T>(items: Vec<T>) -> usize {
 2      items.len()
 3  }
 4  fn main() {
 5      let bag = vec![1.0, 2.0];
 6      let a = handle(bag         );
                             ^
 7      let b = handle(bag);
 8      println!("{} {}", a, b);
 9  }
error[E0382]: use of moved value: `bag`

同じ値を複数の関数呼び出しで使い回したい場合、所有権を渡し切らないようcloneや参照渡しを検討します。

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

この問題を解いてみる →

パターン4

 1  fn summarize<T>(items: Vec<T>) -> usize {
 2      items.len()
 3  }
 4  fn main() {
 5      let records = vec![10, 20, 30];
 6      let a = summarize(records         );
                                  ^
 7      let b = summarize(records);
 8      println!("{} {}", a, b);
 9  }
error[E0382]: use of moved value: `records`

1回目のsummarize呼び出しでrecordsの所有権が消費され、2回目には渡す値が残っていません。

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

この問題を解いてみる →

パターン5

 1  fn tally<T>(items: Vec<T>) -> usize {
 2      items.len()
 3  }
 4  fn main() {
 5      let entries = vec!["x", "y", "z"];
 6      let a = tally(entries         );
                              ^
 7      let b = tally(entries);
 8      println!("{} {}", a, b);
 9  }
error[E0382]: use of moved value: `entries`

関数がVec<T>を借用(&Vec<T>)ではなく所有権ごと受け取る設計になっている点に注意が必要です。

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

この問題を解いてみる →

よくある誤解

「関数に渡すだけなら、値はコピーされて呼び出し元にも残るはず」という思い込みは誤りです。所有権を引数として受け取る関数(&Tではなく単なるT)に渡すと、Copyを実装しない型は消費され尽くします。

まとめ

ジェネリック関数に値を渡すと所有権がムーブされ2回使えないは上級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

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