如何交换数组,切片或Vec的元素? [英] How to swap the elements of an array, slice, or Vec?

查看:33
本文介绍了如何交换数组,切片或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 &muts 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆