Prozedurale Makros: Derive, Function
Vertiefen Sie sich in prozedurale Makros, einschließlich eigener `#[derive]`-Makros und funktionsähnlicher Makros, für komplexere Codegenerierung.
Prozedurale Makros: Derive, Function ist eine kostenlose Learn Rust Coding-Lektion auf CoddyKit. Dies ist Lektion 2 von 3. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Learn Rust Coding-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Learn Rust Coding-Kurs umfasst insgesamt 3 Lektionen.
Teile dieser Lektion wurden noch nicht übersetzt und werden auf Englisch angezeigt.
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!
Häufig gestellte Fragen
Ist die Lektion „Prozedurale Makros: Derive, Function“ kostenlos?
Ja — der vollständige Text von „Prozedurale Makros: Derive, Function“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Learn Rust Coding-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Learn Rust Coding-Kurs umfasst insgesamt 3 Lektionen.
Was lerne ich in „Prozedurale Makros: Derive, Function“?
Vertiefen Sie sich in prozedurale Makros, einschließlich eigener `#[derive]`-Makros und funktionsähnlicher Makros, für komplexere Codegenerierung. Du übst Learn Rust Coding mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Learn Rust Coding zu starten?
Keine Vorkenntnisse erforderlich. Learn Rust Coding auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 3.
Wie lange dauert die Lektion „Prozedurale Makros: Derive, Function“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Learn Rust Coding-Lektion Code schreiben und ausführen?
Ja. Jede Learn Rust Coding-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Deklarative Makros (`macro_rules!`)
- Prozedurale Makros: Derive, Function
- Mit Unsafe Rust arbeiten