Makrá vám umožňujú písať kód, ktorý píše iný kód. Zistite o zvláštnom a mocnom svete metaprogramovania.

Generovanie kódu je funkcia, ktorú nájdete vo väčšine moderných programovacích jazykov. Môže vám pomôcť znížiť štandardný kód a duplikáciu kódu, definovať jazyky špecifické pre doménu (DSL) a implementovať novú syntax.

Rust poskytuje výkonný systém makier, ktorý vám umožňuje generovať kód v čase kompilácie pre sofistikovanejšie programovanie.

Úvod do Rust makier

Makrá sú typom metaprogramovania, ktoré môžete využiť na písanie kódu, ktorý píše kód. V Ruste je makro časť kódu, ktorá generuje iný kód v čase kompilácie.

Rust makrá sú výkonnou funkciou, ktorá vám umožňuje písať kód, ktorý generuje iný kód v čase kompilácie na automatizáciu opakujúcich sa úloh. Rustove makrá pomáhajú znižovať duplicitu kódu a zvyšujú udržiavateľnosť a čitateľnosť kódu.

Makrá môžete použiť na generovanie čohokoľvek od jednoduchých útržkov kódu po knižnice a rámce. Makrá sa líšia od Funkcie hrdze pretože za behu pracujú s kódom a nie s údajmi.

instagram viewer

Definovanie makier v Ruste

Makrá definujete pomocou makro_pravidlá! makro. The makro_pravidlá! makro berie ako vstup vzor a šablónu. Hrdza porovnáva vzor so vstupným kódom a používa šablónu na generovanie výstupného kódu.

Takto môžete definovať makrá v Ruste:

makro_pravidlá! povedz ahoj {
() => {
println!("Ahoj, svet!");
};
}

fnHlavná() {
povedz ahoj!();
}

Kód definuje a povedz ahoj makro, ktoré generuje kód na tlač "Ahoj, svet!". Kód sa zhoduje s () syntax voči prázdnemu vstupu a println! makro vygeneruje výstupný kód.

Tu je výsledok spustenia makra v Hlavná funkcia:

Makrá môžu prevziať vstupné argumenty pre vygenerovaný kód. Tu je makro, ktoré používa jeden argument a generuje kód na tlač správy:

makro_pravidlá! povedať_správa {
($message: expr) => {
println!("{}", $správa);
};
}

The povedať_správu makro vezme $správa argument a vygeneruje kód na tlač argumentu pomocou println! makro. The expr syntax sa zhoduje s argumentom proti akémukoľvek výrazu Rust.

Typy makier hrdze

Rust poskytuje tri typy makier. Každý z typov makier slúži na špecifické účely a má svoju syntax a obmedzenia.

Procedurálne makrá

Procedurálne makrá sa považujú za najvýkonnejší a najuniverzálnejší typ. Procedurálne makrá vám umožňujú definovať vlastnú syntax, ktorá súčasne generuje Rust kód. Procedurálne makrá môžete použiť na vytváranie vlastných odvodených makier, vlastných makier podobných atribútom a vlastných makier podobných funkciám.

Na automatickú implementáciu štruktúr a vlastností enum použijete vlastné odvodené makrá. Populárne balíky ako Serde používajú vlastné odvodené makro na generovanie kódu serializácie a deserializácie pre dátové štruktúry Rust.

Vlastné makrá podobné atribútom sú užitočné na pridávanie vlastných anotácií do kódu Rust. Webový rámec Rocket používa vlastné makro podobné atribútom na stručné a čitateľné definovanie trás.

Na definovanie nových výrazov alebo príkazov Rust môžete použiť vlastné makrá podobné funkciám. Prepravka Lazy_static používa na definovanie vlastné makro podobné funkcii lenivo inicializované statické premenné.

Tu je postup, ako môžete definovať procedurálne makro, ktoré definuje vlastné odvodené makro:

použitie proc_macro:: TokenStream;
použitie citat:: citat;
použitie syn::{DeriveInput, parse_macro_input};

The použitie direktívy importujú potrebné prepravky a typy na písanie procedurálneho makra Rust.

#[proc_macro_derive (MyTrait)]
krčmafnmy_derive_macro(vstup: TokenStream) -> TokenStream {
nech ast = parse_macro_input! (vstup ako DeriveInput);
nech meno = &ast.ident;

nech gen = citát! {
impl MyTrait pre #názov {
// implementácia tu
}
};

gen.into()
}

Program definuje procedurálne makro, ktoré generuje implementáciu vlastnosti pre štruktúru alebo enum. Program vyvolá makro s názvom MyTrait v atribúte derivácie štruktúry alebo enum. Makro trvá a TokenStream objekt ako vstup obsahujúci kód analyzovaný do abstraktného syntaxového stromu (AST) s parse_macro_input! makro.

The názov premenná je odvodená štruktúra alebo identifikátor enum citovať! Makro vygeneruje nový AST predstavujúci implementáciu MyTrait pre typ, ktorý sa nakoniec vráti ako a TokenStream s do metóda.

Ak chcete makro použiť, budete ho musieť importovať z modulu, v ktorom ste ho deklarovali:

// za predpokladu, že ste makro deklarovali v module my_macro_module

použitie my_macro_module:: my_derive_macro;

Pri deklarovaní štruktúry alebo enum, ktoré používa makro, pridáte #[derive (MyTrait)] atribút na začiatok deklarácie.

#[derive (MyTrait)]
štrukturovaťMyStruct {
// polia tu
}

Deklarácia štruktúry s atribútom sa rozširuje na implementáciu MyTrait vlastnosť pre štruktúru:

impl MyTrait pre MyStruct {
// implementácia tu
}

Implementácia vám umožňuje používať metódy v MyTrait vlastnosť na MyStruct prípadov.

Atribút makrá

Makrá atribútov sú makrá, ktoré môžete použiť na položky Rust, ako sú štruktúry, enumy, funkcie a moduly. Makrá atribútov majú formu atribútu, za ktorým nasleduje zoznam argumentov. Makro analyzuje argument na vygenerovanie kódu Rust.

Na pridanie vlastného správania a anotácií do kódu použijete makrá atribútov.

Tu je makro atribútu, ktoré pridáva vlastný atribút do štruktúry Rust:

// import modulov pre definíciu makra
použitie proc_macro:: TokenStream;
použitie citat:: citat;
použitie syn::{parse_macro_input, DeriveInput, AttributeArgs};

#[proc_macro_attribute]
krčmafnmôj_atribút_makro(attr: TokenStream, item: TokenStream) -> TokenStream {
nech args = parse_macro_input!(attr ako AttributeArgs);
nech input = parse_macro_input! (položka ako DeriveInput);
nech meno = &input.ident;

nech gen = citát! {
#vstup
impl #názov {
// vlastné správanie tu
}
};

gen.into()
}

Makro vezme zoznam argumentov a definícia štruktúry a vygeneruje upravenú štruktúru s definovaným vlastným správaním.

Makro berie ako vstup dva argumenty: atribút použitý na makro (analyzovaný s parse_macro_input! makro) a položku (analyzovanú pomocou parse_macro_input! makro). Makro používa citovať! makro na vygenerovanie kódu vrátane pôvodnej vstupnej položky a dodatočnej položky impl blok, ktorý definuje vlastné správanie.

Nakoniec funkcia vráti vygenerovaný kód ako a TokenStream s do() metóda.

Pravidlá makra

Pravidlá makier sú najpriamejším a najflexibilnejším typom makier. Pravidlá makier vám umožňujú definovať vlastnú syntax, ktorá sa v čase kompilácie rozšíri na kód Rust. Pravidlá makier definujú vlastné makrá, ktoré zodpovedajú akémukoľvek výrazu alebo výroku hrdze.

Na generovanie štandardného kódu na abstraktné detaily nízkej úrovne použijete pravidlá makier.

Tu je návod, ako môžete definovať a používať pravidlá makier vo svojich programoch Rust:

makro_pravidlá! make_vector {
( $( $x: expr ),* ) => {
{
nechmut v = Vec::Nový();
$(
v.push($x);
)*
v
}
};
}

fnHlavná() {
nech v = make_vector![1, 2, 3];
println!("{:?}", v); // vytlačí "[1, 2, 3]"
}

Program definuje a make_vector! makro, ktoré vytvorí nový vektor zo zoznamu výrazov oddelených čiarkami v Hlavná funkciu.

Vo vnútri makra sa definícia vzoru zhoduje s argumentmi odovzdanými do makra. The $( $x: expr ),* syntax sa zhoduje so všetkými výrazmi oddelenými čiarkami, ktoré sú označené ako x $.

The $( ) syntax v kóde rozšírenia iteruje každý výraz v zozname argumentov odovzdaných makru po záverečná zátvorka označujúca, že iterácie by mali pokračovať, kým makro nespracuje všetky výrazov.

Zorganizujte svoje hrdzavé projekty efektívne

Rust makrá zlepšujú organizáciu kódu tým, že vám umožňujú definovať opakovane použiteľné vzory kódu a abstrakcie. Makrá vám môžu pomôcť napísať stručnejší a výraznejší kód bez duplikácií v rôznych častiach projektu.

Môžete tiež organizovať programy Rust do prepraviek a modulov pre lepšiu organizáciu kódu, opätovnú použiteľnosť a spoluprácu s inými prepravkami a modulmi.