Macros procédurales : Derive, Function
Découvrez les macros procédurales, notamment les macros personnalisées `#[derive]` et les macros de type fonction, pour générer du code plus complexe.
Macros procédurales : Derive, Function est une leçon Learn Rust Coding gratuite sur CoddyKit. Ceci est la leçon 2 sur 3. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Learn Rust Coding, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Learn Rust Coding comprend 3 leçons au total.
Certaines parties de cette leçon n'ont pas encore été traduites et s'affichent en anglais.
Intro to Procedural Macros
Welcome to the world of procedural macros! Unlike declarative macros (macro_rules!), procedural macros are like functions that operate on Rust code itself.
They take a TokenStream as input, process it, and return another TokenStream. This allows for much more complex code generation.
Types of Procedural Macros
Rust offers three main types of procedural macros:
- Function-like macros: These look and act like regular function calls, e.g.,
my_macro!(...). - Derive macros: These allow you to implement traits automatically for structs and enums using
#[derive(MyTrait)]. - Attribute macros: These allow you to define custom attributes that can be applied to items, e.g.,
#[route("/path")].
The `proc-macro` Crate
Procedural macros must reside in their own special crate type. In your Cargo.toml, you declare it like this:
This tells Cargo that the crate contains macros that transform code at compile time.
[package]
name = "my_macros"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = trueFunction-like Macros Explained
Function-like macros are defined with the #[proc_macro] attribute on a function that takes a proc_macro::TokenStream and returns one.
They're useful for custom DSLs (Domain Specific Languages) or complex code repetition that macro_rules! can't handle.
use proc_macro::TokenStream;
#[proc_macro]
pub fn my_function_macro(input: TokenStream) -> TokenStream {
// Logic to transform input TokenStream
// ...
input // For example, return the input unchanged
}Function-like Macro Example
Here's a conceptual example. A macro `greet_name!` that generates a print statement. The actual implementation would parse the input TokenStream to extract the name.
While the macro definition is complex, its usage is simple and powerful:
/* In 'my_macros/src/lib.rs' */
use proc_macro::TokenStream;
#[proc_macro]
pub fn greet_name(input: TokenStream) -> TokenStream {
// Imagine parsing 'input' to get a name like 'World'
// and generating: println!("Hello, World!");
"println!(\"Hello, {}!\", \"CoddyKit\");".parse().unwrap()
}
/* In 'my_app/src/main.rs' */
use my_macros::greet_name;
fn main() {
greet_name!("CoddyKit");
}Understanding `#[derive]` Macros
Derive macros are the most common type. They allow you to automatically implement a trait for a struct or enum.
When you write #[derive(Debug)], a macro runs at compile time to generate the necessary code for your type to implement the Debug trait.
Implementing a `#[derive]` (Concept)
Custom derive macros are typically built using libraries like syn (for parsing Rust code into an AST) and quote (for generating Rust code from an AST).
You'd define a function annotated with #[proc_macro_derive(MyTrait)] that takes a TokenStream representing the struct/enum and returns the generated trait implementation.
/* In 'my_macros/src/lib.rs' */
use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput};
use quote::quote;
#[proc_macro_derive(MyDebug)] // MyDebug is the trait name
pub fn my_debug_derive(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let name = &ast.ident;
let expanded = quote! {
impl std::fmt::Debug for #name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(stringify!(#name)).finish()
}
}
};
expanded.into()
}Using `#[derive(Debug)]` Example
Let's see a practical example of a derive macro you've likely used: Debug. By adding #[derive(Debug)] to our Point struct, Rust automatically implements the Debug trait, allowing us to print its contents nicely.
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 10, y: 20 };
println!("My point is: {:?}", p);
}Attribute Macros: `#[my_attribute]`
Attribute macros are similar to derive macros but can be applied to any item (functions, structs, modules, etc.). They take the item they are attached to, plus any arguments in parentheses, as input.
Common uses include web framework routing (e.g., #[get("/users")]) or test setup (e.g., #[test]).
/* In 'my_macros/src/lib.rs' */
use proc_macro::TokenStream;
#[proc_macro_attribute]
pub fn log_calls(attr: TokenStream, item: TokenStream) -> TokenStream {
// Imagine adding println! statements to 'item'
item
}
/* In 'my_app/src/main.rs' */
use my_macros::log_calls;
#[log_calls("entry_point")]
fn my_function() {
println!("Inside my_function");
}
fn main() {
my_function();
}When to Use Which Macro
- Function-like macros: For custom mini-languages or complex transformations of arbitrary code blocks.
- Derive macros: For automatically implementing traits on structs and enums.
- Attribute macros: For modifying or generating code around specific items (functions, structs) based on custom attributes.
Each type serves a unique purpose in extending Rust's syntax and capabilities.
Quick Check: Macro Types
Which of the following statements about procedural macros are TRUE?
Recap: Code Generation Power
You've explored the advanced world of procedural macros!
- We learned about function-like macros for custom syntax.
- Understood how
#[derive]macros automate trait implementations. - Briefly touched upon attribute macros for item-level code generation.
Procedural macros are a powerful tool for reducing boilerplate and extending Rust's capabilities, enabling you to write code that writes code!
Questions Fréquemment Posées
La leçon « Macros procédurales : Derive, Function » est-elle gratuite ?
Oui — le texte complet de « Macros procédurales : Derive, Function » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Learn Rust Coding, passe à CoddyKit PRO. Le cours Learn Rust Coding comprend 3 leçons au total.
Qu'est-ce que j'apprendrai dans « Macros procédurales : Derive, Function » ?
Découvrez les macros procédurales, notamment les macros personnalisées `#[derive]` et les macros de type fonction, pour générer du code plus complexe. Tu pratiques Learn Rust Coding avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Learn Rust Coding ?
Aucune expérience préalable n'est requise. Learn Rust Coding sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 3.
Combien de temps prend la leçon « Macros procédurales : Derive, Function » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Learn Rust Coding ?
Oui. Chaque leçon Learn Rust Coding inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Macros déclaratives (`macro_rules!`)
- Macros procédurales : Derive, Function
- Interagir avec Rust non sûr