web-dev-qa-db-fra.com

Quelle est la manière idiomatique Rust de copier / cloner un vecteur dans une fonction paramétrée?

J'essaie d'écrire une fonction paramétrée qui prend un vecteur immuable, le clone ou le copie, fait quelque chose au nouveau vecteur (comme le mélanger) et le renvoie comme nouveau vecteur possédé. Comment cela peut-il être fait et quelle est la façon la plus idiomatique de le faire?

Tentative # 1

pub fn shuffle<T>(vec: &mut [T]) {
    // ... contents removed: it shuffles the vector in place
    // ... so needs a mutable vector
}

pub fn shuffle_create_new<T: Clone>(vec: &[T]) -> Vec<T> {
    let mut newvec = vec.clone();
    shuffle(&mut newvec);
    return newvec.to_owned();
}

Échoue avec:

error[E0596]: cannot borrow immutable borrowed content as mutable
 --> src/main.rs:8:13
  |
8 |     shuffle(&mut newvec);
  |             ^^^^^^^^^^^ cannot borrow as mutable

même si j'ai déclaré newvec comme mutable. Je ne comprends pas pourquoi.

Tentative # 2

pub fn shuffle_owned<T: Clone>(mut vec: Vec<T>) -> Vec<T> {
    shuffle(&mut vec);
    return vec;
}

Bien que cela compile, il ne fait pas ce que je veux. Le vecteur dans lequel vous passez shuffle_owned obtient déplacé dans la fonction, mélangé, puis sa propriété est transférée à l'appelant (via la valeur de retour). Donc, le vecteur d'origine est modifié .

Je veux savoir comment passer dans un vecteur qui pas sera muté, mais les valeurs seront clonées dans un nouveau vecteur encadré et retournées lorsque vous aurez terminé - comme vous le faites dans un langage de programmation fonctionnel qui a des données immuables (comme Clojure).

37
quux00

Votre tentative # 1 est presque correcte, il vous suffit de déplacer to_owned() sur la première ligne:

fn shuffle<T>(vec: &mut [T]) {
    // ...
}

fn shuffle_create_new<T: Clone>(vec: &[T]) -> Vec<T> {
    let mut newvec = vec.to_vec();
    shuffle(&mut newvec);
    newvec
}

Cela se produit car l'appel de clone() sur une tranche vous renverra une tranche (c'est-à-dire &[T]), Et vous ne pouvez pas passer de &[T] À &mut [T] Car vous ne pouvez pas choisir la mutabilité d'une référence (pointeur emprunté). Cependant, lorsque vous appelez to_owned(), vous obtenez une nouvelle instance de Vec<T> Et vous pouvez la placer dans une variable mutable pour obtenir un vecteur mutable.

À partir de Rust 1.0, soit slice::to_vec ou to_owned() de la méthode ToOwned trait peut être utilisé pour créer Vec<T> à partir de &[T].

Il existe également maintenant plusieurs façons d'obtenir &mut [T] À partir de Vec<T>: La notation de découpage (&mut vec[..]), La conversion deref (&mut *vec) Ou l'appel de méthode directe (vec.as_mut_slice(), bien que celle-ci soit déconseillée):

21
Vladimir Matveev

C'est probablement ce que vous voulez:

pub fn copy_shuffle<T: Clone>(vec: &Vec<T>) -> Vec<T> {
    let mut vec = vec.clone();
    shuffle(&mut vec);
    vec
}

ou

pub fn copy_shuffle<T: Clone>(vec: &[T]) -> Vec<T> {
    let mut vec = vec.to_vec();
    shuffle(&mut vec);
    vec
}
8
A.B.