others - rust - 如何同时获取对两个数组元素的可变引用?


fn change(a: &mut i32, b: &mut i32) {


 let c = *a;


 *a = *b;


 *b = c;


}



fn main() {


 let mut v = vec![1, 2, 3];


 change(&mut v[0], &mut v[1]);


}



当我编译上面的代码时,它有错误:


error[E0499]: cannot borrow `v` as mutable more than once at a time


 --> src/main.rs:9:32


 |


9 | change(&mut v[0], &mut v[1]);


 | - ^ - first borrow ends here


 | | |


 | | second mutable borrow occurs here


 | first mutable borrow occurs here



编译器为何禁止它? v[0]v[1]占用不同的内存位置,因此在一起使用它们是不危险的,我遇到这个问题,我该怎么办?

时间:

你可以用这个解决split_at_mut()


let mut v = vec![1, 2, 3];


let (a, b) = v.split_at_mut(1); // Returns (&mut [1], &mut [2, 3])


change(&mut a[0], &mut b[0]); 



有很多安全的事情要做,编译器仍然无法识别,split_at_mut()就是这样,在内部使用unsafe块实现安全抽象。

对于这个问题,我们也可以这样做。下面是我在代码中使用的一些方法,我需要将所有三种情况都分开(1: 索引越界,二: 指数相等,三:单独的索引)。


enum Pair<T> {


 Both(T, T),


 One(T),


 None,


}



fn index_twice<T>(slc: &mut [T], a: usize, b: usize) -> Pair<&mut T> {


 if a == b {


 slc.get_mut(a).map_or(Pair::None, Pair::One)


 } else {


 if a >= slc.len() || b >= slc.len() {


 Pair::None


 } else {


 // safe because a, b are in bounds and distinct


 unsafe {


 let ar = &mut *(slc.get_unchecked_mut(a) as *mut _);


 let br = &mut *(slc.get_unchecked_mut(b) as *mut _);


 Pair::Both(ar, br)


 }


 }


 }


}



你可以使用它,只要你没有巨大的索引,你的索引在编译时就知道了。


#![feature(slice_patterns)]



fn change(a: &mut i32, b: &mut i32) {


 let c = *a;


 *a = *b;


 *b = c;


}



fn main() {


 let mut arr = [5, 6, 7, 8];


 {


 let &mut [ref mut a, _, ref mut b, _..] = &mut arr;


 change(a, b);


 }


 assert_eq!(arr, [7, 6, 5, 8]);


}



请注意,你需要启用功能slice_patterns

方法[T]::iter_mut()返回一个迭代器,它可以为slice 中的每个元素生成一个可变引用,其他集合也有iter_mut方法,这些方法通常封装不安全的代码,但是,它们的接口是完全安全的。

下面是一个通用扩展特性,该特性在片上添加一个方法,可以通过索引返回可变的引用:


pub trait SliceExt {


 type Item;



 fn get_two_mut(&mut self, index0: usize, index1: usize) -> (&mut Self::Item, &mut Self::Item);


}



impl<T> SliceExt for [T] {


 type Item = T;



 fn get_two_mut(&mut self, index0: usize, index1: usize) -> (&mut Self::Item, &mut Self::Item) {


 match index0.cmp(&index1) {


 Ordering::Less => {


 let mut iter = self.iter_mut();


 let item0 = iter.nth(index0).unwrap();


 let item1 = iter.nth(index1 - index0 - 1).unwrap();


 (item0, item1)


 }


 Ordering::Equal => panic!("[T]::get_two_mut(): received same index twice ({})", index0),


 Ordering::Greater => {


 let mut iter = self.iter_mut();


 let item1 = iter.nth(index1).unwrap();


 let item0 = iter.nth(index0 - index1 - 1).unwrap();


 (item0, item1)


 }


 }


 }


}



不能对同一数据生成两个可变引用,这是借用检查器明确禁止的,以防止并发修改,但是,你可以使用unsafe块绕过借用检查器。

在你的案例中v[0]v[1]显然是独立的块,但是,这并不意味着,如果v是一种称为NullMap的映射,那么将所有元素映射到单个字段? 编译器如何在Vec操作v[0];v[1];中知道是安全的,但是,NullMap不是?

如果你试图交换数组的两个元素,为什么不去slice::swap


fn main() {


 let mut v = vec![1, 2, 3];


 v.swap(0,1);


 println!("{:?}",v);


}



另外v需要是mut,因为你正在改变向量,一个不可变的版本将克隆,并且执行交换。

...