Why is indexing a mutable vector based on its len() considered simultaneous borrowing?

♀尐吖头ヾ 提交于 2019-12-04 03:41:59

问题


I know the general answer — You can only borrow mutably once or immutably many times, but not both. I want to know why this specific case is considered simultaneous borrowing.

I have the following code:

fn main() {
    let mut v = vec![1, 2, 3, 4, 5];
    let n = 3;
    // checks on n and v.len() and whatever else...
    let mut s = v[..n].to_vec();
    for i in 0..n {
        v[i + v.len() - n] = s[1];
    }
}

which produces the following error under 1.36.0:

error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
 --> src/main.rs:7:15
  |
7 |         v[i + v.len() - n] = s[1];
  |         ------^-----------
  |         |     |
  |         |     immutable borrow occurs here
  |         mutable borrow occurs here
  |         mutable borrow later used here

It seems that there is no way for the write to v[x] to happen until x is computed, by which time the immutable borrow will be complete. Since the ordering here is completely in series, why doesn't the compiler recognize the dependency and treat these as non-overlapping borrows? Put another way, is there any scenario where this could lead to an actual problem?

Marouane Fazouane suggested concurrency as a possibility, but I don't think this is the case. If there were another thread with a (presumably) mutable reference, it would be a violation to then call v.len(), or to start v[...]. Here, the compiler knows everything that's happening to v — it's a local definition with no other calls. For me, the question is why is this simultaneous borrowing when there's no way for v[] to happen until len() returns. It's akin to v.mutable_call(v.immutable_call());

Incidentally, an earlier version of the compiler (1.28) gave an error that indicated the close bracket as the end of the mutable borrow, so it seemed order is based on the source order, and since the source has the two intermingled, they could be considered overlapping. If so, surely the compiler could improve this...right?

This seems closely related to Why is there a borrow error when no borrowing overlap is occurring?


回答1:


If so, surely the compiler could improve this...right?

Indeed, NLL intentionally started conservatively, as explained in #494341.

Extracting the temporary allows it to compile:

fn main() {
    let mut v = vec![1, 2, 3, 4, 5];
    let n = 3;
    // checks on n and v.len() and whatever else...
    let s = v[..n].to_vec();
    for i in 0..n {
        let index = i + v.len() - n;
        v[index] = s[1];
    }
}

This makes it clear that the issue is strictly one of not computing the index before attempting to use it.

Since it is not possible to start the call to IndexMut<Idx>::index_mut(&mut self, index: Idx) before computing the Idx, there is no reason to start the mutable borrow of v before computing the index.

1Courtesy of trentcl.



来源:https://stackoverflow.com/questions/57406018/why-is-indexing-a-mutable-vector-based-on-its-len-considered-simultaneous-borr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!