Pour modéliser des données complexes en Rust, vous disposez de deux outils puissants : les structs (structures) et les enums. Combinés au pattern matching, ils permettent d’écrire du code expressif, exhaustif et sans cas non gérés. Dans cette unité, vous verrez comment définir vos propres types de données et les manipuler de façon idiomatique.
Les structs : regrouper des données
Une struct est un type composite qui regroupe plusieurs champs nommés sous un même type. C’est l’équivalent des objets dans d’autres langages, mais sans héritage.
struct Reference {
identifiant: String,
prefixe: String,
numero: u32,
annee: u16,
}
fn main() {
let r = Reference {
identifiant: String::from("DOC-2024-001"),
prefixe: String::from("DOC"),
numero: 1,
annee: 2024,
};
println!("Ref : {} ({})", r.identifiant, r.annee);
}
Méthodes avec impl
On ajoute des méthodes à une struct avec un bloc impl. Le premier paramètre &self (ou &mut self) représente l’instance courante.
impl Reference {
// Méthode associée (constructeur)
fn new(prefixe: &str, numero: u32, annee: u16) -> Self {
Reference {
identifiant: format!("{}-{}-{:03}", prefixe, annee, numero),
prefixe: prefixe.to_string(),
numero,
annee,
}
}
// Méthode d'instance
fn formater(&self) -> String {
format!("[{}] #{:04}/{}", self.prefixe, self.numero, self.annee)
}
}
fn main() {
let r = Reference::new("DOC", 42, 2024);
println!("{}", r.formater()); // "[DOC] #0042/2024"
}
Les enums : des types à variantes
Les enums Rust sont bien plus puissantes que dans la plupart des langages : chaque variante peut contenir des données de types différents.
enum FormatRef {
Court, // pas de données
Long(String), // contient une String
Numerique { annee: u16, num: u32 }, // champs nommés
}
fn afficher(format: &FormatRef) -> String {
match format {
FormatRef::Court => "format court".to_string(),
FormatRef::Long(s) => format!("long: {}", s),
FormatRef::Numerique { annee, num } => format!("{}/{}", annee, num),
}
}
Pattern matching avec match
L’expression match est l’outil fondamental pour travailler avec les enums. Le compilateur vérifie que tous les cas sont couverts (exhaustivité).
let score = 85;
let mention = match score {
90..=100 => "Excellent",
75..=89 => "Bien",
60..=74 => "Assez bien",
_ => "Insuffisant", // cas par défaut
};
println!("Mention : {}", mention);
if let pour un seul cas
Quand vous ne vous intéressez qu’à un seul variant, if let est plus concis qu’un match complet :
let maybe_ref: Option<String> = Some("DOC-2024-001".to_string());
if let Some(ref_doc) = maybe_ref {
println!("Référence trouvée : {}", ref_doc);
} else {
println!("Aucune référence");
}
Derive : dériver des traits automatiquement
L’attribut #[derive] génère automatiquement des implémentations de traits courants :
#[derive(Debug, Clone, PartialEq)]
struct Reference {
identifiant: String,
numero: u32,
}
fn main() {
let r = Reference { identifiant: "DOC-001".to_string(), numero: 1 };
println!("{:?}", r); // Debug : affiche la struct formatée
let r2 = r.clone(); // Clone : copie la valeur
}
- Les structs groupent des champs nommés ; les méthodes s’ajoutent dans un bloc
impl - Les enums Rust peuvent contenir des données dans chaque variante
matchest exhaustif : le compilateur force la gestion de tous les cas#[derive(Debug)]permet d’afficher une struct avec{:?}
📚 Formation : Rust : Développer des utilitaires système

-
Add a note