Cannot borrow as immutable because it is also borr

2019-01-03 03:22发布

What is going on here (playground)?

struct Number {
    num: i32
}

impl Number {
    fn set(&mut self, new_num: i32) {
        self.num = new_num;
    }
    fn get(&self) -> i32 {
        self.num
    }
}

fn main() {
    let mut n = Number{ num: 0 };
    n.set(n.get() + 1);
}

Gives this error:

error[E0502]: cannot borrow `n` as immutable because it is also borrowed as mutable
  --> <anon>:17:11
   |
17 |     n.set(n.get() + 1);
   |     -     ^          - mutable borrow ends here
   |     |     |
   |     |     immutable borrow occurs here
   |     mutable borrow occurs here

However if you simply change the code to this it works:

fn main() {
    let mut n = Number{ num: 0 };
    let tmp = n.get() + 1;
    n.set(tmp);
}

To me those look exactly equivalent - I mean, I would expect the former to be transformed to the latter during compilation. Doesn't Rust evaluate all function parameters before evaluating the next-level-up function call?

1条回答
乱世女痞
2楼-- · 2019-01-03 04:11

This line:

n.set(n.get() + 1);

is desugared into

Number::set(&mut n, n.get() + 1);

The error message might be a bit more clear now:

error[E0502]: cannot borrow `n` as immutable because it is also borrowed as mutable
  --> <anon>:18:25
   |
18 |     Number::set(&mut n, n.get() + 1);
   |                      -  ^          - mutable borrow ends here
   |                      |  |
   |                      |  immutable borrow occurs here
   |                      mutable borrow occurs here

As Rust evaluates arguments left to right, that code is equivalent to this:

let arg1 = &mut n;
let arg2 = n.get() + 1;
Number::set(arg1, arg2);

It should now be obvious what is wrong. Swapping those first two lines, fixes this, but Rust does not do that kind of control-flow analysis.

This was first created as bug #6268, now it is integrated into RFC 811.

As of 1.25.0-nightly 2018-01-13, it is possible to use non-lexical lifetimes. If you run your example on nightly Rust and enable the NLL feature gate using #![feature(nll)], it will now compile without an error.

查看更多
登录 后发表回答