如何交换数组、切片或 Vec 的元素? [英] How to swap the elements of an array, slice, or Vec?
问题描述
我想使用库函数交换切片 data
的元素,但由于多次借用而不起作用:
I want to swap elements of slice data
using library function, but it doesn't work because of multiple borrowing:
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
|
可以手动完成,但我不认为每次都使用此代码很好:
It could be done manually, but I don't think using this code every time is great:
let temp = data[i];
data[i] = data[j];
data[j] = temp;
是否有其他解决方案可以在切片中交换元素?
Is there any other solution to swap elements in slices?
推荐答案
有一个 swap
方法 在切片上:data.swap(i, j)
.
原始代码不起作用,因为该语言要求 &mut
不能使用别名,也就是说,如果一段数据可以通过 &mut访问代码>,那么肯定没有其他方法可以使用该数据.一般来说,对于连续索引
data[i]
、data[j]
,编译器不能保证i
和j代码>不同.如果它们相同,则索引指的是相同的内存,因此
&mut data[i]
和 &mut data[j]
将是两个指向相同的数据:非法!
The original code doesn't work because the language requires that &mut
s do not alias, that is, if a piece of data is accessible via an &mut
, then there must be no other way to use that data. In general, for successive indexes data[i]
, data[j]
, the compiler cannot guarantee that i
and j
are different. If they are the same then the indexing is referring to the same memory and so &mut data[i]
and &mut data[j]
would be two pointers to the same data: illegal!
.swap
在内部使用了一些 unsafe
代码,确保正确处理 i == j
情况,避免别名 >&mut
指针.也就是说,它没有必须使用unsafe
,它只是为了确保这个原始"操作具有高性能(我绝对可以想象未来的语言/库通过使需要的不变量更容易表达来减少对不安全的需求的改进,例如以下是一个安全的实现:
.swap
uses a bit of unsafe
code internally, being sure to handle the i == j
case correctly, avoiding aliasing &mut
pointers. That said, it doesn't have to use unsafe
, it is only to ensure this "primitive" operation has high-performance (and I could definitely imagine future language/library improvements that reduce the need for unsafe here by making the require invariants easier to express), e.g. the following is a safe implementation:
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
:该语言提供了原始"功能,而库在这些功能之上构建了其余功能).
The key here is split_at_mut
which separates the slice into two disjoint halves (this is done using unsafe
internally, but Rust's standard library is built on unsafe
: the language provides "primitive" features and the libraries build the rest on top of them).
这篇关于如何交换数组、切片或 Vec 的元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!