在vector索引操作中难以理解不可变借用和可变借用

  • 本文关键字:不可变 索引 vector 操作 rust
  • 更新时间 :
  • 英文 :


我刚开始使用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
}

最新更新