【问题标题】:How to swap the elements of an array, slice, or Vec?如何交换数组、切片或 Vec 的元素?
【发布时间】:2015-04-02 09:39:16
【问题描述】:

我想使用库函数交换切片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;

有没有其他解决方案可以交换切片中的元素?

【问题讨论】:

  • “可以像往常一样手动完成” ...Copy 类型 - 否则将导致“无法移出索引内容”。

标签: arrays vector rust slice


【解决方案1】:

切片上有一个swap methoddata.swap(i, j)

原始代码不起作用,因为该语言要求&muts 不使用别名,也就是说,如果可以通过&mut 访问一条数据,那么一定没有其他方法可以使用该数据.一般来说,对于连续的索引data[i]data[j],编译器不能保证ij是不同的。如果它们相同,则索引指向相同的内存,因此&mut data[i]&mut data[j] 将是指向相同数据的两个指针:非法!

.swap 在内部使用了一些 unsafe 代码,确保正确处理 i == j 大小写,避免混淆 &mut 指针。也就是说,它没有必须使用unsafe,它只是为了确保这个“原始”操作具有高性能(我绝对可以想象未来的语言/库改进会减少需求通过使 require 不变量更易于表达,这里不安全),例如以下是一个安全的实现:

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 构建的:该语言提供“原始”功能并且库构建其余的都在上面)。

【讨论】:

  • 里面没有魔法 - 只是不安全的块 - 真可怜!)
  • @FominArseniy,它可以用一些“魔法”来实现以避免unsafe(我已经编辑了我的答案以包含一个示例实现)。
  • @FominArseniy,如果类型为Copy,它仅适用于临时变量。如果包含的类型发生移动(例如data: &amp;mut [String]),则无法使用您在问题中提供的代码,而我给出的谨慎代码确实有效。
  • @FominArseniy,是的,它是指针版本,它是通过以下方式实现的切片过程:github.com/rust-lang/rust/blob/master/src/libcore/slice.rs#L352
猜你喜欢
  • 2020-06-10
  • 2014-05-30
  • 2013-02-02
  • 1970-01-01
  • 2015-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多