ProgrammationDéveloppeur Backend

Quelles sont les particularités du travail avec les collections HashSet et HashMap en Rust ? Comment gérer la possession des clés et des valeurs, et quels sont les dangers d'une utilisation incorrecte ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

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

  • Lors de l'ajout d'un élément, la collection prend (move) la clé/la valeur, à moins qu'une référence ou un type copiable ne soit utilisé.
  • Il est possible de modifier en toute sécurité le contenu uniquement via une référence mutable à HashMap/HashSet.

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 :

  • Les clés dans HashMap/HashSet doivent implémenter Hash, Eq
  • L'insertion d'un élément déplace toujours (move) la variable dans la collection
  • Il est sûr d'extraire des valeurs uniquement tant que la collection n'est pas modifiée (règles d'emprunt)

Questions pièges.

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.

Erreurs typiques et anti-patterns

  • Utiliser une référence à une clé temporaire lors de la recherche (vivre aussi longtemps que map)
  • Implémenter Hash/Eq pour des structures complexes sans prendre en compte tous les champs (risque de collisions ou de comparaisons incohérentes)
  • Modifier la structure de HashMap lors du parcours des références à ses valeurs

Exemple de la vie réelle

Cas négatif

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 :

  • Code évident du point de vue d'un débutant

Inconvénients :

  • Erreur de compilation — impossible d'emprunter simultanément de manière mutable et non mutable

Cas positif

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 :

  • Pas de violations de possession, code prévisible
  • Sécurité des types

Inconvénients :

  • Surcopie, si la valeur est lourde