How to swap the elements of an array, slice, or Vec?

后端 未结 1 1672
半阙折子戏
半阙折子戏 2020-12-11 15:10

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() {
          


        
相关标签:
1条回答
  • 2020-12-11 15:22

    There's a swap method on slices: data.swap(i, 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 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]);
    }
    

    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).

    0 讨论(0)
提交回复
热议问题