error[E0502]: cannot borrow `data` as mutable because it is also borrowed as immutable

error[E0502]: cannot borrow `data` as immutable because it is also borrowed as mutable

同じ参照先への不変参照と可変参照は共存できない。このルールはコンパイラによる静的解析や最適化に利用できるだけでなく、取得系操作と更新系操作の分離を促進することで、コードの可読性も高める。

注意点

このエラー自体のルールは単純である。

しかし、エラーを読み解くには、参照まわりのその他の知識も必要になる事がある。

例えば、『ライフタイムの延長』の影響があると、初見では納得しにくいエラーになる。

メッセージ

メッセージの構成はだいたい以下のようになる。

要約部
  • 同時使用が検出された参照先の変数名
  • 不変参照中の可変参照か?可変参照中の不変参照か?
詳細部

(不変参照中の可変参照の場合)

  • 不変参照の発生個所 ← エラー個所より前方
  • 可変参照の発生個所 ← エラー個所
  • 不変参照の使用箇所 ← エラー個所より後方

パターン

パターン A1

不変参照中の可変参照

不変参照中に可変参照を行うパターン。

サンプル


fn main() {
    let mut data = 0;
    let data_ref = &data;
    *&mut data = 1;
    println!("{}", data_ref);
}

error[E0502]: cannot borrow `data` as mutable because it is also borrowed as immutable
 --> src\main.rs:4:6
  |
3 |     let data_ref = &data;
  |                    ----- immutable borrow occurs here
4 |     *&mut data = 1;
  |      ^^^^^^^^^ mutable borrow occurs here
5 |     println!("{}", data_ref);
  |                    -------- immutable borrow later used here

パターン A2

可変参照中の不変参照

可変参照中に不変参照を行うパターン。

サンプル


fn main() {
    let mut data = 0;
    let data_mut = &mut data;
    println!("{}", &data);
    *data_mut = 1;
}

error[E0502]: cannot borrow `data` as immutable because it is also borrowed as mutable
 --> src\main.rs:4:20
  |
3 |     let data_mut = &mut data;
  |                    --------- mutable borrow occurs here
4 |     println!("{}", &data);
  |                    ^^^^^ immutable borrow occurs here
5 |     *data_mut = 1;
  |     ------------- mutable borrow later used here

パターン B

Drop トレイトの影響

詳しくは『Drop トレイトのライフタイムへの影響 - ライフタイムの延長』を参照。
(注: Drop トレイトを直接的に扱っていなくても考慮が必要。)

サンプル


fn main() {
    let mut var = 0;
    let _refs = MyRef(&var);
    *&mut var = 1;
}

struct MyRef<'a>(&'a i32);
impl Drop for MyRef<'_> {
    fn drop(&mut self) {
        println!("ID [{}] is drpoped.", self.0)
    }
}

error[E0502]: cannot borrow `var` as mutable because it is also borrowed as immutable
 --> src\main.rs:4:6
  |
3 |     let _refs = MyRef(&var);
  |                       ---- immutable borrow occurs here
4 |     *&mut var = 1;
  |      ^^^^^^^^ mutable borrow occurs here
5 | }
  | - immutable borrow might be used here, when `_refs` is dropped and runs the `Drop` code for type `MyRef`