Phase 3 — Structures de données
#12 Collections
Vec, HashMap, itérateurs
Les vecteurs (Vec<T>)
Un Vec<T> est un tableau dynamique : il peut grandir ou rétrécir pendant l'exécution du programme. C'est la collection la plus utilisée en Rust.
Créer et manipuler un Vec
fn main() {
// Créer un vecteur vide
let mut nombres: Vec<i32> = Vec::new();
nombres.push(1);
nombres.push(2);
nombres.push(3);
// Raccourci avec la macro vec!
let fruits = vec!["pomme", "banane", "cerise"];
println!("Fruits : {:?}", fruits);
println!("Nombre de fruits : {}", fruits.len());
// Accéder aux éléments
let premier = &fruits[0]; // panique si hors limites
let deuxieme = fruits.get(1); // retourne Option<&T>
println!("Premier : {}", premier);
println!("Deuxième : {:?}", deuxieme);
}Opérations courantes sur Vec
Opérations sur les vecteurs
let mut v = vec![1, 2, 3, 4, 5];
v.push(6); // ajouter à la fin
v.pop(); // retirer le dernier -> Some(6)
v.insert(0, 0); // insérer à l'index 0
v.remove(0); // retirer l'élément à l'index 0
v.contains(&3); // true
v.sort(); // trier sur place
v.reverse(); // inverser l'ordreLes HashMaps
Un HashMap<K, V> stocke des paires clé-valeur. Il faut l'importer depuis std::collections.
Utiliser un HashMap
use std::collections::HashMap;
fn main() {
let mut populations = HashMap::new();
// Insérer des paires clé-valeur
populations.insert("Paris", 2_161_000);
populations.insert("Lyon", 516_000);
populations.insert("Marseille", 870_000);
// Accéder à une valeur
if let Some(pop) = populations.get("Paris") {
println!("Population de Paris : {}", pop);
}
// Modifier une valeur
populations.insert("Lyon", 520_000); // remplace l'ancienne
// Entry : insérer seulement si absent
populations.entry("Toulouse").or_insert(486_000);
// Parcourir toutes les entrées
for (ville, pop) in &populations {
println!("{} : {} habitants", ville, pop);
}
}Les itérateurs
Les itérateurs sont au coeur de Rust. Chaque collection peut être transformée en itérateur avec .iter(), .iter_mut() ou.into_iter().
Les trois types d'itérateurs
let nombres = vec![1, 2, 3];
// iter() : emprunte les éléments (&T)
for n in nombres.iter() {
println!("{}", n);
}
// iter_mut() : emprunte de manière mutable (&mut T)
let mut nombres = vec![1, 2, 3];
for n in nombres.iter_mut() {
*n *= 2;
}
// nombres est maintenant [2, 4, 6]
// into_iter() : consomme le vecteur (T)
let nombres = vec![1, 2, 3];
for n in nombres.into_iter() {
println!("{}", n);
}
// nombres n'est plus utilisable iciMéthodes courantes (map, filter, collect)
Les itérateurs proposent des méthodes fonctionnelles puissantes pour transformer et filtrer les données.
map, filter, collect
fn main() {
let nombres = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// filter : garder seulement les pairs
// map : les doubler
// collect: rassembler dans un nouveau Vec
let pairs_doubles: Vec<i32> = nombres
.iter()
.filter(|&&n| n % 2 == 0)
.map(|&n| n * 2)
.collect();
println!("Nombres pairs doublés : {:?}", pairs_doubles);
// [4, 8, 12, 16, 20]
// Autres méthodes utiles
let somme: i32 = nombres.iter().sum();
let produit: i32 = nombres.iter().product();
let max = nombres.iter().max(); // Some(&10)
let min = nombres.iter().min(); // Some(&1)
let any_pair = nombres.iter().any(|&n| n % 2 == 0); // true
let all_positifs = nombres.iter().all(|&n| n > 0); // true
}À vous de jouer
Essayez les commandes ci-dessous pour compiler et exécuter le programme :
terminal — cargo