Има swap
метод за срезове: data.swap(i, j)
.
Оригиналният код не работи, защото езикът изисква &mut
s да не създават псевдоними, тоест, ако дадена част от данните е достъпна чрез &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
: езикът предоставя „примитивни“ функции и библиотеките изграждат останалото върху тях).
person
huon
schedule
03.02.2015
Copy
типа - в противен случай това ще доведе до невъзможност за преместване от индексираното съдържание. - person Andrey Tyukin   schedule 10.01.2019