Énumérations et motifs en Rust
Introduction
Comme pour les structures, les personnes ayant programmé dans divers langages seront familières de l’énumération. L’énumération existe notamment dans le langage C# et aussi en C++.
En langage Rust, comme en C# ou en C++, les énumérations permettent de définir une série de constantes dont chacune aura un nom. Le langage Rust va cependant bien plus loin : il peut unir au sein d’une énumération des types différents. Et comme nous sommes en Rust, cette union s’effectue sous le contrôle vigilant du compilateur.
Une notion propre à Rust, les motifs, est utilisée entre autres avec les énumérations. Nous les étudierons également dans ce chapitre. D’ores et déjà, nous pouvons les décrire comme des sortes d’expressions régulières dédiées aux données incluses dans les structures, les tuples et toutes sortes de structures de données Rust.
Les énumérations en Rust
1. Premiers exemples
On commence par créer un projet dédié à nos premières énumérations et à leurs manipulations :
cargo new first_enums --bin
Tout d’abord, on définit une énumération de quelques premiers départements français :
enum Departement{
Ain,
Aisne,
Allier,
AlpesDeHauteProvence,
HautesAlpes,
AlpesMaritimes,
Ardeche,
Ardennes,
Ariege
}
Si on veut se référer à un des champs de l’énumération, on utilise cette syntaxe, par exemple avec le département de l’Ain :
Departement::Ain
On peut stocker une valeur d’énumération dans une variable :
let ain : Departement = Departement::Ain;
Si l’on veut afficher la valeur, il faut en revanche ajouter un trait prédéfini à l’énumération (comme nous l’avons fait dans le chapitre précédent avec les structures). Un chapitre ultérieur est consacré exclusivement aux traits. Pour pouvoir utiliser le trait prédéfini Debug, il faut le préciser ainsi grâce à la ligne suivante placée au-dessus de la définition de l’énumération :
#[derive(Debug)]
La définition de l’énumération devient la suivante :
#[derive(Debug)]
enum Departement{
Ain,
Aisne,
Allier,
AlpesDeHauteProvence,
HautesAlpes,
AlpesMaritimes,
Ardeche,
Ardennes,
Ariege
}
Maintenant, nous pouvons afficher une des valeurs de l’énumération :
let ain : Departement = Departement::Ain;
println!("{:?}", ain);
Ce qui nous donne ceci en sortie dans la console :
> Ain
Retirons (commentons-le) le trait utilisé ici (Debug) pour lire le message d’erreur que l’on obtiendrait du compilateur. Comme vous le voyez, les conseils donnés...
Filtrage par motif
1. Premier exemple, pour rappel
On commence par créer un projet pour les motifs :
cargo new motifs --bin
> Created binary (application) `motifs` package
Reprenons un petit exemple pour illustrer le filtrage par motif en général, spécialement dans le cas d’une énumération.
Imaginons une structure qui contient plusieurs sortes de personnages d’un monde merveilleux : Héros, Magicien, Fantôme et Combattant.
-
Héros est défini en tant que structure Unité.
-
Fantôme et Combattant le sont en tant que structure à champs nommés, mais avec un nombre de champs différent entre les deux.
-
Magicien est défini en tant que structure Tuple.
On a de ce fait ce code :
enum Personnage{
Heros,
Fantome { points_de_vie : u32, indice_invisibilite : u32},
Combattant { points_de_vie : u32},
Magicien(u32, u32),
}
On crée plusieurs de ces personnages :
let h = Personnage::Heros;
let f = Personnage::Fantome{points_de_vie : 25,
indice_invisibite : 12};
let c = Personnage::Combattant{points_de_vie : 35};
let m = Personnage::Magicien(34, 78);
Maintenant, on voudrait bien une unique fonction à même de nous retourner les données précises qui composent chaque personnage. On ne peut pas demander directement à l’énumération, il faut donc utiliser un filtrage par motif. C’est ce que l’on fait dans l’implémentation de la fonction suivante. On utilise donc le mot-clé match :
fn filtrage_par_motif(entree : Personnage) -> String {
match entree{
Personnage::Heros
=> format!("Le héros va très bien."),
Personnage::Fantome{ points_de_vie, indice_invisibilite }
=> format!("Point...