如何交换数组、切片或 Vec 的元素?
How to swap the elements of an array, slice, or Vec?
我想使用库函数交换 slice data
的元素,但由于多次借用它不起作用:
use std::mem;
fn example() {
let mut data = [1, 2, 3];
let i = 0;
let j = 1;
mem::swap(&mut data[i], &mut data[j]);
}
error[E0499]: cannot borrow `data[_]` as mutable more than once at a time
--> src/lib.rs:8:29
|
8 | mem::swap(&mut data[i], &mut data[j]);
| --------- ------------ ^^^^^^^^^^^^ second mutable borrow occurs here
| | |
| | first mutable borrow occurs here
| first borrow later used by call
|
可以手动完成,但我不认为每次都使用此代码很好:
let temp = data[i];
data[i] = data[j];
data[j] = temp;
是否有任何其他解决方案来交换切片中的元素?
切片上有一个 swap
method:data.swap(i, j)
。
原来的代码不行,因为语言要求&mut
不要别名,也就是说,如果一段数据可以通过&mut
访问,那么一定没有使用该数据的其他方式。一般来说,对于连续的索引data[i]
、data[j]
,编译器不能保证i
和j
是不同的。如果它们相同,则索引引用相同的内存,因此 &mut data[i]
和 &mut data[j]
将是指向相同数据的两个指针:非法!
.swap
在内部使用了一些 unsafe
代码,确保正确处理 i == j
情况,避免别名 &mut
指针。也就是说,没有使用unsafe
,只是为了确保这个"primitive"操作具有高性能(我完全可以想象未来language/library 通过使要求不变量更容易表达来减少对不安全的需求的改进),例如以下是一个安全的实现:
use std::cmp::Ordering;
use std::mem;
fn swap<T>(x: &mut [T], i: usize, j: usize) {
let (lo, hi) = match i.cmp(&j) {
// no swapping necessary
Ordering::Equal => return,
// get the smallest and largest of the two indices
Ordering::Less => (i, j),
Ordering::Greater => (j, i),
};
let (init, tail) = x.split_at_mut(hi);
mem::swap(&mut init[lo], &mut tail[0]);
}
这里的关键是 split_at_mut
它将切片分成两个不相交的部分(这是在内部使用 unsafe
完成的,但是 Rust 的标准库是建立在 unsafe
之上的:语言提供"primitive" 功能和库在它们之上构建其余部分)。
我想使用库函数交换 slice data
的元素,但由于多次借用它不起作用:
use std::mem;
fn example() {
let mut data = [1, 2, 3];
let i = 0;
let j = 1;
mem::swap(&mut data[i], &mut data[j]);
}
error[E0499]: cannot borrow `data[_]` as mutable more than once at a time
--> src/lib.rs:8:29
|
8 | mem::swap(&mut data[i], &mut data[j]);
| --------- ------------ ^^^^^^^^^^^^ second mutable borrow occurs here
| | |
| | first mutable borrow occurs here
| first borrow later used by call
|
可以手动完成,但我不认为每次都使用此代码很好:
let temp = data[i];
data[i] = data[j];
data[j] = temp;
是否有任何其他解决方案来交换切片中的元素?
切片上有一个 swap
method:data.swap(i, j)
。
原来的代码不行,因为语言要求&mut
不要别名,也就是说,如果一段数据可以通过&mut
访问,那么一定没有使用该数据的其他方式。一般来说,对于连续的索引data[i]
、data[j]
,编译器不能保证i
和j
是不同的。如果它们相同,则索引引用相同的内存,因此 &mut data[i]
和 &mut data[j]
将是指向相同数据的两个指针:非法!
.swap
在内部使用了一些 unsafe
代码,确保正确处理 i == j
情况,避免别名 &mut
指针。也就是说,没有使用unsafe
,只是为了确保这个"primitive"操作具有高性能(我完全可以想象未来language/library 通过使要求不变量更容易表达来减少对不安全的需求的改进),例如以下是一个安全的实现:
use std::cmp::Ordering;
use std::mem;
fn swap<T>(x: &mut [T], i: usize, j: usize) {
let (lo, hi) = match i.cmp(&j) {
// no swapping necessary
Ordering::Equal => return,
// get the smallest and largest of the two indices
Ordering::Less => (i, j),
Ordering::Greater => (j, i),
};
let (init, tail) = x.split_at_mut(hi);
mem::swap(&mut init[lo], &mut tail[0]);
}
这里的关键是 split_at_mut
它将切片分成两个不相交的部分(这是在内部使用 unsafe
完成的,但是 Rust 的标准库是建立在 unsafe
之上的:语言提供"primitive" 功能和库在它们之上构建其余部分)。