Code Fix

中級

E0502: cannot borrow as mutable because it is also borrowed as immutable

不変参照が生きている(後で使われる)間に、同じ変数を可変で借用しようとするとE0502エラーになります。Rustの借用規則は「不変参照は何個でも、可変参照は同時に1つだけ」を強制します。

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

error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
E0502
エラーコード — `rustc --explain E0502` で詳しい説明が見られます
cannot borrow `v` as mutable because it is also borrowed as immutable
詳細メッセージ — 何が問題だったか

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

パターン1

 1  fn main() {
 2      let mut v = vec![1, 2, 3];
 3      let first = &v[0];
 4      v.push(4);  
              ^
 5      println!("{}", first);
 6  }
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable

firstというvへの不変参照がまだ使われる予定がある間は、vを変更する可変借用(push)は許されません。

直し方: v.push(4); を (空) にします。

この問題を解いてみる →

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

パターン2

 1  fn main() {
 2      let mut nums = vec![10, 20, 30];
 3      let head = &nums[0];
 4      nums.push(40); 
               ^
 5      println!("{}", head);
 6  }
error[E0502]: cannot borrow `nums` as mutable because it is also borrowed as immutable

不変参照headが生きている間にnumsをpushで変更しようとすると、借用チェッカーがコンパイル時に止めます。

直し方: nums.push(40); を (空) にします。

この問題を解いてみる →

パターン3

 1  fn main() {
 2      let mut names = vec![String::from("a")];
 3      let first_name = &names[0];
 4      names.push(String::from("b"));
                       ^
 5      println!("{}", first_name);
 6  }
error[E0502]: cannot borrow `names` as mutable because it is also borrowed as immutable

不変参照と可変参照は同時に存在できません。参照を使い終わってから変更する必要があります。

直し方: names.push(String::from("b")); を (空) にします。

この問題を解いてみる →

パターン4

 1  fn main() {
 2      let mut prices = vec![100, 200];
 3      let cheapest = &prices[0];
 4      prices.push(50);
                ^
 5      println!("{}", cheapest);
 6  }
error[E0502]: cannot borrow `prices` as mutable because it is also borrowed as immutable

参照が有効な間は元のVecへの変更操作(追加や並べ替え)は一切できません。

直し方: prices.push(50); を (空) にします。

この問題を解いてみる →

パターン5

 1  fn main() {
 2      let mut scores = vec![70, 80];
 3      let top = &scores[1];
 4      scores.push(90); 
                ^
 5      println!("{}", top);
 6  }
error[E0502]: cannot borrow `scores` as mutable because it is also borrowed as immutable

Vecへの追加は内部でメモリの再確保が起きうるため、既存の参照との共存を許すと危険です。

直し方: scores.push(90); を (空) にします。

この問題を解いてみる →

よくある誤解

「参照を作った後でも、元の変数を自由に変更できるはず」という思い込みは誤りです。不変参照がまだ使われる予定がある間は、その変数自体を変更する可変借用は一切できません。

実務での勘所

この規則は、Rustでは「エイリアシングと可変性は同時に許さない(aliasing XOR mutability)」と呼ばれる、借用チェッカー全体を支える中心的な原則の一例です。複数の不変参照が同時に存在してもよいが、可変参照が存在する間はそれ以外のいかなる参照も許さない、というルールを徹底することで、ガベージコレクタ無しでもメモリ安全性を保証できます。この原則のおかげで、C++でVectorを反復しながら要素を追加・削除してイテレータが無効化される、という事故が、Rustではコンパイルの時点でそもそも起こり得ません。

演習をはじめる

関連するエラー

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