问题描述
我知道一般的答案——你只能可变地借用一次或一成不变地借用多次,但不能同时借用.我想知道为什么这个特定案例被认为是同时借款.
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.
我有以下代码:
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 下产生以下错误:
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
似乎在计算 x
之前无法写入 v[x]
,届时不可变借用将完成.既然这里的排序是完全串联的,为什么编译器不识别依赖并将它们视为不重叠的借用?换句话说,有没有可能导致实际问题的情况?
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?
MarouaneFazouane 建议将并发作为一种可能性,但我认为情况并非如此.如果有另一个线程具有(大概)可变引用,则调用 v.len()
或启动 v[...]
将是违规的.在这里,编译器知道 v
发生的一切——它是一个没有其他调用的本地定义.对我来说,问题是当 v[]
在 len()
返回之前不可能发生时,为什么要同时借用.它类似于 v.mutable_call(v.immutable_call());
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());
顺便说一下,早期版本的编译器 (1.28) 给出了一个错误,表明右括号是可变借用的结尾,所以看起来顺序是基于源顺序的,而且由于源将两者混合在一起,它们可以被视为重叠.如果是这样,编译器肯定可以改进这一点……对吗?
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?
推荐答案
确实,NLL 有意保守地开始,如 #49434.
Indeed, NLL intentionally started conservatively, as explained in #49434.
提取临时文件允许它编译:
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.
由于在计算 Idx
之前不可能开始调用 IndexMut::index_mut(&mut self, index: Idx)
,有没有理由在计算索引之前启动 v
的可变借用.
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.
由 trentcl 提供.
这篇关于为什么基于 len() 索引可变向量被认为是同时借用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!