为什么基于基于len()的可变向量建立索引被视为同时借用?

时间:2019-08-08 06:01:43

标签: rust borrow-checker

我知道一般的答案-您只能一次或多次多次可变借贷,但不能两次都借。我想知道为什么将这种特定情况视为同时借款。

我有以下代码:

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];
    }
}

在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

在计算v[x]之前,似乎没有办法进行对x的写操作,此时将完成不可变的借用。由于此处的顺序完全是连续的,因此编译器为什么不识别依赖项,并将其视为非重叠借项?换句话说,是否存在任何可能导致实际问题的情况?

Marouane Fazouane suggested concurrency as a possibility,但我认为情况并非如此。如果存在另一个具有(可能是)可变引用的线程,则调用v.len()或启动v[...]是违反的。在这里,编译器知道v发生的一切-这是一个本地定义,没有其他调用。对我来说,问题是为什么v[]直到len()返回之前都无法发生,所以为什么同时借用。类似于v.mutable_call(v.immutable_call());

顺便说一句,早期版本的编译器(1.28)给出了一个错误,指示在可变借位的结尾处使用了右括号,因此似乎顺序是基于源顺序的,并且由于源将两者混合在一起,它们可以被认为是重叠的。如果是这样,肯定编译器可以改善这一点...对吗?

这似乎与Why is there a borrow error when no borrowing overlap is occurring?

密切相关

1 个答案:

答案 0 :(得分:5)

  

如果是这样,肯定编译器可以改善这一点...对吗?

实际上,NLL故意保守地开始,如#49434 1 中所述。

提取临时文件可以对其进行编译:

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];
    }
}

这清楚表明,问题完全是在尝试使用索引之前不计算索引的问题之一。

由于在计算IndexMut<Idx>::index_mut(&mut self, index: Idx)之前无法启动对Idx的调用,因此没有理由在计算索引之前启动v的可变借位。

1 trentcl提供。