Rust で「cannot borrow as mutable more than once」(E0499) が解決できない
同じ値に対する可変参照は同時に 1 つしか持てない。
E0499 は 2 つ目の &mut を作ったときに出る。
借用のスコープを分ける、インデックスで扱う、split_at_mut や RefCell を使う、のいずれかで解決する。
公開: 更新:
要約
E0499 は、同じ値に対する可変参照を 2 つ同時に作ったときに出る。
Rust の借用規則では「不変参照は何個でも、可変参照は 1 つだけ」で、この 2 つは同時に成立しない。
let mut i = 0;
let x = &mut i;
let a = &mut i; // error[E0499]: cannot borrow `i` as mutable more than once at a time
*x += 1;借用が「いつまで生きているか」で判定されるため、2 つ目を作った行が悪いとは限らない。
1 つ目を最後に使う位置を動かすだけで通ることも多い。
実行例
実際に上記の手順を rust:1 で動かすと、2 つ目の &mut i を作るコードは E0499 で止まり、コンパイラは 1 つ目の借用が *x += 1 の行まで続いていることを示した。
スコープを分ける・インデックスで扱う・split_at_mut・RefCell の 4 通りはいずれもコンパイルが通り、それぞれ 2、[1, 2, 3, 11]、[4, 2, 3, 4]、1 を出力した。
$ rustc bad.rs
error[E0499]: cannot borrow `i` as mutable more than once at a time
--> bad.rs:4:13
|
3 | let x = &mut i;
| ------ first mutable borrow occurs here
4 | let a = &mut i; // 2 つ目の可変参照
| ^^^^^^ second mutable borrow occurs here
5 | *x += 1;
| ------- first borrow later used here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0499`.
終了コード: 1$ rustc solve_scope.rs$ ./solve_scope
2$ rustc solve_index.rs$ ./solve_index
[1, 2, 3, 11]$ rustc solve_split.rs$ ./solve_split
[4, 2, 3, 4]$ rustc solve_refcell.rs$ ./solve_refcell
1— 2026-09-11 時点の出力
検証環境
- 検証日
- 実行環境
rust:1Debian GNU/Linux 13 (trixie)- バージョン
- Python 3.13.5
- Git 2.47.3
この記事の「実行例」は、上記の環境で実際にコマンドを実行して得られた出力をそのまま掲載しています。 再現手順はリポジトリの検証スクリプトとして管理し、定期的に再実行して出力を更新しています。
よくある原因
- 借用が重なっている: 1 つ目の
&mutを後の行で使っていると、その時点まで借用が続く。
間に 2 つ目を作れば衝突する。 - 借りたままコレクションを変更している: 要素への
&mutを持ったままpushすると、再確保で参照が無効になりうるためコンパイラが止める。 - 同じ
Vecの 2 要素を同時に取ろうとしている:&mut v[0]と&mut v[1]は、コンパイラからは同じvへの二重借用に見える。 &mut selfメソッドの二重呼び出し: 引数の中で自分自身の可変メソッドを呼ぶと重なる。
解決策
1. 借用のスコープを分ける
let mut i = 0;
{
let x = &mut i;
*x += 1;
} // ここで x の借用が終わる
let a = &mut i;
*a += 1;明示的なブロックを使わなくても、1 つ目を使い終えた後なら 2 つ目を作れる。
借用は最後の使用位置までしか続かない。
2. 参照ではなくインデックスや値で扱う
let mut v = vec![1, 2, 3];
let first = v[0]; // i32 は Copy なので借用が残らない
v.push(first + 10);3. 2 要素同時なら split_at_mut を使う
let mut v = vec![1, 2, 3, 4];
let (left, right) = v.split_at_mut(2);
left[0] += right[0];標準ライブラリが「重ならないこと」を保証してくれるため、二重借用にならない。
4. どうしても共有が要るなら RefCell
use std::cell::RefCell;
let cell = RefCell::new(0);
*cell.borrow_mut() += 1;借用チェックがコンパイル時から実行時に移るだけなので、重なればパニックする。
設計を見直せるならまず 1 〜 3 を試す。
詳細は参照と借用の章(新しいタブで開く)にある。