我刚开始使用Rust。对于这段代码,我在理解可变和不可变借款方面有一些困难。这是我正在测试的代码。
fn main() {
let mut list = vec![1,2,3,4,5,6];
let i = 2;
list[list[i]] = list[list[i-1]];
}
在编译时,我得到以下错误:
error[E0502]: cannot borrow `list` as immutable because it is also borrowed as mutable
--> src/main.rs:4:7
|
4 | list[list[i]] = list[list[i-1]];
| -----^^^^----
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
| mutable borrow later used here
error: aborting due to previous error
当我用下面的代码替换上面的代码片段时,
fn main() {
let mut list = vec![1,2,3,4,5,6];
let i = 2;
let index = list[i];
list[index] = list[list[i-1]];
}
代码可以很好地编译和执行。
我的问题是为什么编译器没有将此标记为这样的错误?
5 | list[index] = list[list[i-1]];
| --------------| |
| | | immutable borrow occurs here
| | immutable borrow occurs here
| mutable borrow occurs here
| mutable borrow later used here
赋值的右边不是不可变的借用吗?为什么只将第一个代码片段标记为错误?
Rust是否有类似于c++中的happens-before或sequenced before关系,以确保右边的不可变借用在左边的可变借用之前被排序,因此它不是错误?如果上一个问题的答案是肯定的,那么为什么编译器不能在内部将list[list[i]]
序列为let tmp = list[i]; list[tmp]=...
?
下面是演示相同问题的一些代码,但是稍微简化了一下。
fn main() {
let mut list: Vec<usize> = vec![1,2,3,4,5,6];
let i: usize = 2;
let place: &mut usize = &mut list[list[i]];
*place = 3;
}
显然,编译器正在做这样的事情:
fn main() {
let mut list: Vec<usize> = vec![1,2,3,4,5,6];
let i: usize = 2;
// mutable borrow of list starts
let r: &mut Vec<usize> = &mut list;
// immutable borrow of list starts
let q: usize = list[i];
// immutable borrow of list ends
// mutable borrow of r starts
let place: &mut usize = &mut r[q];
// place is a mutable borrow derived from r
*place = 3;
// place is dropped, mutable borrow of r ends
// r is dropped, mutable borrow of list ends
}
下面的代码运行正常:
fn main() {
let mut list: Vec<usize> = vec![1,2,3,4,5,6];
let i: usize = 2;
let q: usize = list[i]; // immutable borrow begins and ends
let place: &mut usize = &mut list[q]; // mutable borrow begins
*place = 3; // mutable borrow ends
}