我想使用库函数交换切片data
的元素,但由于多次借用它不起作用:
mem::swap(&mut data[i], &mut data[j]); //error
可以像往常一样手动完成:
let temp = data[i];
data[i] = data[j];
data[j] = temp;
但我不认为每次使用此代码都很棒。是否有任何其他解决方案通常使用库交换切片?
答案 0 :(得分:19)
切片上有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
,它只是为了确保这种“原始”操作具有高性能(我可以想象未来的语言/库改进会减少通过使需求不变量更容易表达,这里需要不安全,例如以下是一个安全的实施:
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
上构建的:该语言提供了“原始” “功能和库构建了其余部分。”