如何交换数组、切片或 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 methoddata.swap(i, j)

原来的代码不行,因为语言要求&mut不要别名,也就是说,如果一段数据可以通过&mut访问,那么一定没有使用该数据的其他方式。一般来说,对于连续的索引data[i]data[j],编译器不能保证ij是不同的。如果它们相同,则索引引用相同的内存,因此 &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" 功能和库在它们之上构建其余部分)。