我知道一般的答案-您只能一次或多次多次可变借贷,但不能两次都借。我想知道为什么将这种特定情况视为同时借款。
我有以下代码:
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?
密切相关答案 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提供。