7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Rustでmutable borrow occurs hereのエラーが出るが理由が分からない

Last updated at Posted at 2022-01-24

以下のようなプログラムがRustでコンパイルできず、ちょっと悩んだのでメモ。
皆さんは、以下のプログラムをぱっと見てエラーの理由が分かるでしょうか?

b.rs
struct Banana {
    vals: Vec<usize>,
}
impl Banana {
    fn cut(&mut self) {
        println!("cut");
        // 本来はここで self.vals の値を変更する
    }
}
fn test(a: &mut Banana) {
    for v in a.vals.iter() { // --- (*1)
        println!("{}", v);
        a.cut(); // --- (*2) ここでエラーが出る!! 
    }
}
fn main() {
    let mut a = Banana{vals:vec![1,2,3]};
    test(&mut a);
}

コマンドライン上で $rustc b.rs を実行するとエラーが出て動きません。

error[E0502]: cannot borrow `*a` as mutable because it is also borrowed as immutable
  --> b.rs:14:9
   |
12 |     for v in a.vals.iter() {
   |              -------------
   |              |
   |              immutable borrow occurs here
   |              immutable borrow later used here
13 |         println!("{}", v);
14 |         a.cut();
   |         ^^^^^^^ mutable borrow occurs here

error: aborting due to previous error

なぜ動かないのか?

エラーを日本語でよくよく確認すると「*aが不変としても借用されるため、不変として借用することはできません」とのこと。

(*1)でa.vals.iter()を実行することで、aがイミュータブル(不変)な借用として使われるのに、(*2)でcutを呼び出すことで、aを&mut a(可変な参照)として扱おうとしているためエラーが出るのです。

つまり、同じスコープ内で、変数をミュータブルとイミュータブルの両方として利用するのが問題なのです。

簡単な修正例1

そこで、動作がちょっと変わってしまいますが、関数cutを呼び出すタイミングを以下のようにforループ外に移動すれば動きます。

fix_b.rs
fn test(a: &mut Banana) {
    for v in a.vals.iter() {
        println!("{}", v);
        // a.cut(); ループ外に出す
    }
    a.cut();
}

簡単な修正例2

あるいは、もしも可能であるなら関数cutの引数を&mutから&に変更します。これにより、イミュータブルな借用になります。

fix_b.rs
impl Banana {
    fn cut(&self) {
        println!("cut");
    }
}

また、コメント欄で @namn1125 さんがより完全な修正例を出してくださっています。ありがとうございます!

ボローチェッカーは優秀なのですが、時によく考えないと修正方法が分からないことも多いです。
for文との組み合わせにも注意しましょう。

参考

以下で、エラーメッセージと解決のヒントというPDFを無料で配布しています。良かったら見てください!

7
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?