Lär dig programmera i Rust · Lektion

Procedurmakron: Derive och Function

Fördjupa er i procedurmakron, inklusive anpassade `#[derive]`-makron och funktionsliknande makron, för mer komplex kodgenerering.

Lektion 2 av 312 steg

Procedurmakron: Derive och Function är en gratis lektion i Lär dig programmera i Rust på CoddyKit. Detta är lektion 2 av 3. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Lär dig programmera i Rust, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Lär dig programmera i Rust innehåller totalt 3 lektioner.

Introduktion till procedurmakron

Välkommen till procedurmakronas värld! Till skillnad från deklarativa makron (macro_rules!) fungerar procedurmakron som funktioner som arbetar direkt med Rust-kod.

De tar emot en TokenStream som indata, bearbetar den och returnerar en annan TokenStream. Detta möjliggör mycket mer komplex kodgenerering.

Typer av procedurmakron

Rust erbjuder tre huvudtyper av procedurmakron:

  • Funktionsliknande makron: Dessa ser ut och fungerar som vanliga funktionsanrop, till exempel my_macro!(...).
  • Derive-makron: Dessa låter dig automatiskt implementera traits för structs och enums med hjälp av #[derive(MyTrait)].
  • Attributmakron: Dessa låter dig definiera anpassade attribut som kan tillämpas på olika objekt, till exempel #[route("/path")].

Crate:n `proc-macro`

Procedurmakron måste finnas i sin egen särskilda crate-typ. I din Cargo.toml deklarerar du den så här:

Detta talar om för Cargo att craten innehåller makron som transformerar kod vid kompilering.

[package]
name = "my_macros"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true

Funktionsliknande makron förklarade

Funktionsliknande makron definieras med attributet #[proc_macro] på en funktion som tar emot en proc_macro::TokenStream och returnerar en sådan.

De är användbara för anpassade DSL:er (domänspecifika språk) eller komplex kodupprepning som macro_rules! inte kan hantera.

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
}

Exempel på ett funktionsliknande makro

Här är ett konceptuellt exempel. Ett makro `greet_name!` som genererar en utskriftssats. Den faktiska implementationen skulle tolka indata-TokenStream för att hämta namnet.

Själva makrodefinitionen är komplex, men användningen är enkel och kraftfull:

/* 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");
}

Förstå makron med `#[derive]`

Derive-makron är den vanligaste typen. De låter dig automatiskt implementera ett trait för en struct eller enum.

När du skriver #[derive(Debug)] körs ett makro vid kompilering för att generera den kod som krävs för att din typ ska implementera traitet Debug.

Implementera en `#[derive]` (koncept)

Anpassade derive-makron byggs vanligtvis med bibliotek som syn (för att tolka Rust-kod till ett AST) och quote (för att generera Rust-kod från ett AST).

Du definierar en funktion med annoteringen #[proc_macro_derive(MyTrait)] som tar emot en TokenStream som representerar structen eller enumen och returnerar den genererade trait-implementationen.

/* 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()
}

Exempel på användning av `#[derive(Debug)]`

Vi tittar på ett praktiskt exempel på ett derive-makro som du sannolikt redan har använt: Debug. Genom att lägga till #[derive(Debug)] i vår Point-struct implementerar Rust automatiskt traitet Debug, så att vi kan skriva ut dess innehåll på ett tydligt sätt.

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 10, y: 20 };
    println!("My point is: {:?}", p);
}

Attributmakron: `#[my_attribute]`

Attributmakron liknar derive-makron, men kan tillämpas på vilket objekt som helst (funktioner, structs, moduler med mera). De tar objektet de är kopplade till, tillsammans med eventuella argument inom parentes, som indata.

Vanliga användningsområden är routing i webbramverk (till exempel #[get("/users")]) eller konfiguration av tester (till exempel #[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();
}

När ska du använda vilket makro

  • Funktionsliknande makron: För anpassade miniatyrspråk eller komplexa transformationer av godtyckliga kodblock.
  • Derive-makron: För att automatiskt implementera traits för structs och enums.
  • Attributmakron: För att ändra eller generera kod runt specifika objekt (funktioner, structs) utifrån anpassade attribut.

Varje typ har ett eget användningsområde när Rusts syntax och funktionalitet ska utökas.

Snabbtest: makrotyper

Vilka av följande påståenden om procedurmakron är sanna?

Sammanfattning: kraftfull kodgenerering

Du har utforskat den avancerade världen av procedurmakron!

  • Vi har lärt oss om funktionsliknande makron för anpassad syntax.
  • Vi har förstått hur #[derive]-makron automatiserar trait-implementationer.
  • Vi har kort berört attributmakron för kodgenerering på objektnivå.

Procedurmakron är ett kraftfullt verktyg för att minska mängden standardkod och utöka Rusts funktionalitet, så att du kan skriva kod som skriver kod!

Gratis att börja

Lär dig Rust med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
39
Lektioner
144

Vanliga frågor

Är lektionen ”Procedurmakron: Derive och Function” gratis?

Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Lär dig programmera i Rust, inklusive ”Procedurmakron: Derive och Function”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Lär dig programmera i Rust innehåller totalt 3 lektioner.

Vad lär jag mig i ”Procedurmakron: Derive och Function”?

Fördjupa er i procedurmakron, inklusive anpassade `#[derive]`-makron och funktionsliknande makron, för mer komplex kodgenerering. Ni övar på Lär dig programmera i Rust med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Lär dig programmera i Rust?

Du behöver inga förkunskaper. Utbildningen i Lär dig programmera i Rust på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 3.

Hur lång tid tar lektionen ”Procedurmakron: Derive och Function”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Lär dig programmera i Rust-lektionen?

Ja. Varje Lär dig programmera i Rust-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Deklarativa makron (`macro_rules!`)
  2. Procedurmakron: Derive och Function
  3. Interagera med Unsafe Rust
← Tillbaka till Lär dig programmera i Rust