En Rust, les macros permettent de générer du code au moment de la compilation, fournissant des outils puissants pour la méta-programmation, la réduction du boilerplate et la mise en œuvre de DSL. Les principaux types de macros :
macro_rules!.#[derive], attributs (#[some_macro]) et function-like (custom_macro!()).Les macros déclaratives sont plus simples à utiliser pour du code modèle, tandis que les macros procédurales offrent plus de contrôle sur la syntaxe et l'analyse des jetons.
Exemple de macro déclarative :
macro_rules! vec_of_strings { ($($x:expr),*) => { { let mut v = Vec::new(); $(v.push($x.to_string());)* v } }; } let v = vec_of_strings!("a", "b"); // => Vec<String>
Exemple de macro procédurale (exemple derive) :
#[derive(Debug, Clone)] struct MyStruct; // le derive Debug est implémenté par une macro procédurale dans std.
Les macros Rust peuvent-elles générer du code syntaxiquement incorrect ou du code avec des erreurs d'exécution ?
Réponse : Oui, les macros ne vérifient pas la validité des dépliements au moment de l'écriture ; les erreurs peuvent apparaître uniquement après que le compilateur a remplacé la macro. Les macros déclaratives peuvent entraîner des erreurs syntaxiques non évidentes. Les macros procédurales peuvent générer du code incorrect ou vulnérable, donc il est crucial de tester leur fonctionnement soigneusement.
Exemple :
macro_rules! make_error { () => { let x = ; // une erreur syntaxique surviendra lors de l'utilisation de la macro } }
Histoire
Dans un grand projet, pour réduire le boilerplate, ils ont utilisé macro_rules!, sans couvrir tous les cas de motifs. Un utilisateur a accidentellement passé une expression non supportée à la macro, ce qui a conduit à une erreur de compilation incompréhensible, dont la cause était difficile à retracer.
Histoire
Lors du transfert de macros procédurales entre les crates, des problèmes de compatibilité des versions de l'API TokenStream sont survenus, ce qui a provoqué le blocage de l'IDE, et l'erreur ne se manifestait que lors des builds no_std.
Histoire
Lors de l'écriture d'un DSL pour les configurations avec une macro procédurale, un parsing dangereux des jetons d'entrée a été réalisé (sans validation des types), ce qui a rendu apparaître des bugs étranges, des vulnérabilités et une incapacité à déployer correctement une partie des nouvelles fonctionnalités.