Historique de la question
Les collections HashSet et HashMap sont des structures standard de std::collections, qui implémentent une recherche rapide par hachage. Elles sont intégrées à Rust depuis les premières versions du langage, mais les détails internes de leur utilisation posent souvent des problèmes même aux développeurs expérimentés à cause du système de possession.
Problème
La confusion se produit lors de l'insertion et de l'extraction d'éléments (surtout si les valeurs ne sont pas Copy), lors des modifications de la collection (emprunts muables), ainsi que lors de l'utilisation de références comme clés. Il y a également un problème d'implémentation correcte de Eq/Hash pour les types personnalisés.
Solution
Exemple de code :
use std::collections::HashMap; fn main() { let mut map = HashMap::new(); map.insert("key", 42); if let Some(value) = map.get("key") { println!("Valeur trouvée : {}", value); } }
Particularités clés :
Peut-on obtenir plusieurs références muables sur le même élément HashMap ?
Non, le vérificateur d'emprunts ne le permettra pas pour éviter des violations de possession.
Peut-on utiliser le littéral de chaîne "abc" directement comme clé de HashMap<String, V> ?
Non, on s'attend à un String précis, et "abc" est un &'static str. Une conversion est nécessaire : insert("abc".to_string(), val).
Peut-on extraire une valeur de HashMap, en la conservant dans une variable séparée, et continuer à utiliser HashMap ?
Oui, on peut prendre une référence à la valeur via get — mais si l'on fait remove (ou l'on extrait par move), alors HashMap est muté et toutes les anciennes références deviennent invalides.
Tentative d'emprunter simultanément la clé et la valeur, puis de muter la collection :
let mut map = HashMap::new(); map.insert("abc".to_string(), 10); let val = map.get("abc"); map.insert("def".to_string(), 20); // erreur de l'emprunteur
Avantages :
Inconvénients :
Extraction de la valeur, travail uniquement avec sa copie ou clone :
let mut map = HashMap::new(); map.insert("abc".to_string(), 10); if let Some(val) = map.get("abc") { let val = *val; // on copie map.insert("def".to_string(), 20); // tout fonctionne }
Avantages :
Inconvénients :