Les enums en Rust diffèrent radicalement des enums en C/C++ : ils peuvent stocker des données associées et sont idéaux pour la modélisation de l'état et des erreurs. Ils permettent de construire des machines à états finis typées, différents types d'Option/Result, et d'implémenter le pattern "sum types". Historiquement, des constructions analogues étaient utilisées dans les langages de programmation fonctionnels pour décrire les variantes d'une entité avec des options strictement séparées.
Problème : obtenir de l'expressivité (exprimer tous les états possibles), où chaque cas de traitement est obligatoire, et il est impossible de négliger une branche accidentellement. Les erreurs à l'échelle du projet sont difficiles à typer sans une telle structure expressive.
Solution : les enums avec des données associées et le pattern matching offrent du contrôle — chaque branche est vérifiée par le compilateur, l'exhaustivité est garantie. De plus, pour Result et Option, de nombreux outils auxiliaires sont déjà disponibles.
Exemple de code :
enum NetworkState { Disconnected, Connecting(u32), // numéro de tentative Connected(String), Error(String), } fn print_state(state: NetworkState) { match state { NetworkState::Disconnected => println!("Net : déconnecté"), NetworkState::Connecting(count) => println!("Net : connexion (tentative {})", count), NetworkState::Connected(addr) => println!("Net : connecté à {}", addr), NetworkState::Error(msg) => println!("Erreur réseau : {}", msg), } }
Caractéristiques clés :
Est-il possible de traiter partiellement les branches d'un enum sans _ ?
Le compilateur interdit les cas non couverts pour les enums non exhaustifs, mais si vous utilisez _, les branches non traitées seront "absorbées". Il convient d'éviter _ pour les branches critiques afin que des modifications futures ne passent pas inaperçues.
Dans quels cas les valeurs associées sont-elles référencées, et dans quels cas sont-elles copiées lors du pattern matching ?
Lors du pattern matching, les données associées sont, par défaut, déplacées (move). Si vous souhaitez uniquement consulter, utilisez des références :
match &state { NetworkState::Connected(addr) => println!("par référence : {}", addr), _ => {} }
Peut-on utiliser deux enums avec des variantes de noms qui se chevauchent dans une même structure ?
Oui, mais les noms des variantes sont utilisés avec le préfixe de l'enum. Cela empêche les collisions et rend le code auto-documenté (par exemple, Status::Ok vs NetworkState::Ok).
_ pour masquer de nouvelles variantes lors de l'extension d'un enum_ =>) dans des gestionnaires d'erreurs critiquesDans le code, le traitement de Result<T, E> a toujours un catch-all via _ =>, et de nouvelles erreurs (lors de l'extension de l'enum) passent inaperçues — des pertes d'erreurs silencieuses se produisent.
Avantages :
Inconvénients :
On utilise le matching d'exhaustivité, chaque variante de l'enum est traitée explicitement, soit un panic pour une branche sans comportement connu.
Avantages :
Inconvénients :