web-dev-qa-db-fra.com

Utilisation de la carte avec des vecteurs

Bien que les vecteurs conviennent mieux à la programmation procédurale, je voudrais utiliser une fonction map sur eux. L'extrait de code suivant fonctionne:

fn map<A, B>(u: &Vec<A>, f: &Fn(&A) -> B) -> Vec<B> {
    let mut res: Vec<B> = Vec::with_capacity(u.len());
    for x in u.iter() {
        res.Push(f(x));
    }
    res
}

fn f(x: &i32) -> i32 {
    *x + 1
}

fn main() {
    let u = vec![1, 2, 3];
    let v = map(&u, &f);
    println!("{} {} {}", v[0], v[1], v[2]);
}

Pourquoi n'y a-t-il pas une telle fonction dans la bibliothèque standard? (et aussi dans std::collections::LinkedList). Y a-t-il une autre façon de gérer cela?

41
user19018

Rust aime être plus général que ça; le mappage se fait sur des itérateurs, plutôt que sur des vecteurs ou des tranches uniquement.

Quelques démonstrations:

let u = vec![1, 2, 3];
let v: Vec<_> = u.iter().map(f).collect();
let u = vec![1, 2, 3];
let v = u.iter().map(|&x| x + 1).collect::<Vec<_>>();

.collect() est probablement la partie la plus magique de celui-ci, et vous permet de rassembler tous les éléments de l'itérateur dans une grande variété de types différents, comme le montre le les implémenteurs de FromIterator . Par exemple, un itérateur de Ts peut être collecté dans Vec<T>, De chars peut être collecté dans un String, de (K, V) Paires à un HashMap<K, V>, etc.

Cette façon de travailler avec les itérateurs signifie également que vous n’avez souvent même pas besoin de créer des vecteurs intermédiaires là où dans d’autres langues ou avec d’autres techniques vous le feriez; c'est plus efficace et généralement tout aussi naturel.

64
Chris Morgan

Comme indiqué par bluss , vous pouvez également utiliser l'itérateur mutable pour muter la valeur en place, sans changer le type:

let mut nums = nums;
for num in &mut nums { *num += 1 }
println!("{:p} - {:?}", &nums, nums);

La fonction Vec::map_in_place a été déconseillé dans Rust 1.3 et n'est plus présent dans Rust 1.4.

La réponse de Chris Morgan est la meilleure solution 99% du temps. Cependant, il existe une fonction spécialisée appelée Vec::map_in_place . Cela a l'avantage de ne nécessiter aucune allocation de mémoire supplémentaire, mais cela nécessite que le type d'entrée et de sortie soit de la même taille ( merci Levans ) et est actuellement instable:

fn map_in_place<U, F>(self, f: F) -> Vec<U> 
    where F: FnMut(T) -> U

Un exemple:

#![feature(collections)]

fn main() {
    let nums = vec![1,2,3];
    println!("{:p} - {:?}", &nums, nums);

    let nums = nums.map_in_place(|v| v + 1);
    println!("{:p} - {:?}", &nums, nums);
}
14
Shepmaster