Как поменять местами элементы массива?
Я хочу поменять местами элементы slice data использование функции библиотеки, но она не работает из-за нескольких заимствований:
mem::swap(&mut data[i], &mut data[j]); //error
Это можно сделать вручную, как обычно:
let temp = data[i];
data[i] = data[j];
data[j] = temp;
но я не думаю, что использование этого кода каждый раз здорово. Есть ли другое решение для использования библиотеки swap для срезов обычно?
1 ответов
здесь swap метод на ломтики: data.swap(i, j).
исходный код не работает, потому что язык требует, чтобы &muts не псевдоним, то есть, если часть данных доступна через &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: язык предоставляет "примитивные" функции, а библиотеки строят остальные поверх них).