Makrokomandos leidžia rašyti kodą, kuris rašo kitą kodą. Sužinokite apie keistą ir galingą metaprogramavimo pasaulį.

Kodo generavimas yra funkcija, kurią rasite daugelyje šiuolaikinių programavimo kalbų. Tai gali padėti sumažinti pagrindinį kodą ir kodo dubliavimą, apibrėžti domenui būdingas kalbas (DSL) ir įdiegti naują sintaksę.

Rust yra galinga makrokomandų sistema, leidžianti kompiliavimo metu generuoti kodą sudėtingesniam programavimui.

Įvadas į rūdžių makrokomandas

Makrokomandos yra metaprogramavimo tipas, kurį galite panaudoti norėdami parašyti kodą, kuris rašo kodą. Rust makrokomanda yra kodo dalis, kuri kompiliavimo metu generuoja kitą kodą.

Rūdžių makrokomandos yra galinga funkcija, leidžianti rašyti kodą, kuris kompiliavimo metu generuoja kitą kodą, kad būtų galima automatizuoti pasikartojančias užduotis. Rust makrokomandos padeda sumažinti kodo dubliavimą ir pagerinti kodo priežiūrą bei skaitomumą.

Naudodami makrokomandas galite generuoti bet ką – nuo ​​paprastų kodo fragmentų iki bibliotekų ir sistemų. Makrokomandos skiriasi nuo

instagram viewer
Rūdžių funkcijos nes jie veikia kodu, o ne duomenimis vykdymo metu.

Makrokomandų apibrėžimas rūdyje

Makrokomandas nustatysite naudodami makro_taisyklės! makrokomandą. The makro_taisyklės! makrokomandos įvestis paima šabloną ir šabloną. Rust suderina šabloną su įvesties kodu ir naudoja šabloną išvesties kodui generuoti.

Štai kaip galite apibrėžti makrokomandas Rust:

makro_taisyklės! sakyk labas {
() => {
println!("Labas pasauli!");
};
}

fnpagrindinis() {
sakyk labas!();
}

Kodas apibrėžia a sakyk labas makrokomandą, kuri generuoja kodą spausdinti „Sveikas, pasauli!“. Kodas atitinka () sintaksė prieš tuščią įvestį ir println! makrokomandos generuoja išvesties kodą.

Štai makrokomandos paleidimo rezultatas pagrindinis funkcija:

Makrokomandos gali priimti sugeneruoto kodo įvesties argumentus. Štai makrokomanda, kuri naudoja vieną argumentą ir generuoja kodą pranešimui spausdinti:

makro_taisyklės! say_message {
($pranešimas: expr) => {
println!("{}", $pranešimas);
};
}

The say_message makro paima $pranešimas argumentą ir generuoja kodą, kad išspausdintų argumentą naudodami println! makrokomandą. The expr sintaksė atitinka argumentą prieš bet kokią Rust išraišką.

Rūdžių makrokomandų tipai

Rust siūlo trijų tipų makrokomandas. Kiekvienas iš makrokomandų tipų tarnauja tam tikriems tikslams ir turi savo sintaksę bei apribojimus.

Procedūrinės makrokomandos

Procedūrinės makrokomandos laikomos galingiausiu ir universaliausiu tipu. Procedūrinės makrokomandos leidžia apibrėžti pasirinktinę sintaksę, kuri vienu metu generuoja Rust kodą. Galite naudoti procedūrines makrokomandas, kad sukurtumėte pasirinktines išvestines makrokomandas, pasirinktines atributų makrokomandas ir pasirinktines funkcijas panašias makrokomandas.

Naudosite pasirinktines išvestines makrokomandas, kad automatiškai įdiegtumėte struktūras ir enum bruožus. Populiarūs paketai, tokie kaip „Serde“, naudoja pasirinktinę išvestinę makrokomandą, kad sukurtų „Rust“ duomenų struktūrų serializacijos ir deserializacijos kodus.

Į tinkintus atributus panašios makrokomandos yra patogios norint pridėti pasirinktinių komentarų prie Rust kodo. „Rocket“ žiniatinklio sistema naudoja tinkintą į atributą panašią makrokomandą, kad glaustai ir skaitomai apibrėžtų maršrutus.

Galite naudoti tinkintas funkcijas panašias makrokomandas, kad apibrėžtumėte naujas Rust išraiškas arba teiginius. „Lazy_static“ dėžė naudoja tinkintą į funkciją panašią makrokomandą, kad apibrėžtų tinginys-inicializuotas statiniai kintamieji.

Štai kaip galite apibrėžti procedūrinę makrokomandą, kuri apibrėžia tinkintą išvestinę makrokomandą:

naudoti proc_macro:: TokenStream;
naudoti citata:: citata;
naudoti syn::{DeriveInput, parse_macro_input};

The naudoti direktyvos importuoja reikalingas dėžes ir tipus Rust procedūrinei makrokomandai rašyti.

#[proc_macro_derive (MyTrait)]
pubfnmano_išvestinė_makrokomanda(įvestis: TokenStream) -> TokenStream {
leisti ast = parse_macro_input!(input kaip DeriveInput);
leisti vardas = &ast.ident;

leisti gen = citata! {
impl ManoTrait dėl #vardas {
// įgyvendinimas čia
}
};

gen.into()
}

Programa apibrėžia procedūrinę makrokomandą, kuri generuoja struktūros ar enum bruožo įgyvendinimą. Programa iškviečia makrokomandą pavadinimu ManoTrait išvestiniame struktūros arba enum atribute. Makrokomandas paima a TokenStream objektas kaip įvestis, kurioje yra kodas, išanalizuotas į abstrakčią sintaksės medį (AST) su parse_macro_input! makrokomandą.

The vardas kintamasis yra išvestinis struktūros arba enum identifikatorius, the citata! Makrokomandas sukuria naują AST, atspindintį įgyvendinimą ManoTrait tipui, kuris galiausiai grąžintas kaip a TokenStream su į metodas.

Norėdami naudoti makrokomandą, turėsite importuoti makrokomandą iš modulio, kuriame ją deklaravote:

// darant prielaidą, kad makrokomandą paskelbėte modulyje my_macro_module

naudoti mano_makro_modulis:: mano_išvestinis_makrokomandas;

Deklaruodami struktūrą arba enum, kuri naudoja makrokomandą, pridėsite #[išvesti (MyTrait)] atributas deklaracijos viršuje.

#[išvesti (MyTrait)]
struktūra„MyStruct“. {
// čia laukai
}

Struktūros deklaracija su atributu išplečiama į įgyvendinimą ManoTrait struktūros bruožas:

impl ManoTrait dėl MyStruct {
// įgyvendinimas čia
}

Įgyvendinimas leidžia naudoti metodus ManoTrait bruožas ant „MyStruct“. atvejų.

Atributų makrokomandos

Atributų makrokomandos yra makrokomandos, kurias galite taikyti „Rust“ elementams, pvz., struktūroms, sąrašams, funkcijoms ir moduliams. Atributų makrokomandos yra atributo, po kurio pateikiamas argumentų sąrašas, forma. Makrokomandas analizuoja argumentą, kad sugeneruotų Rust kodą.

Naudosite atributų makrokomandas, kad prie kodo pridėtumėte tinkintus veiksmus ir komentarus.

Štai atributo makrokomanda, kuri prideda pasirinktinį atributą prie „Rust“ struktūros:

// makrokomandos apibrėžimo modulių importavimas
naudoti proc_macro:: TokenStream;
naudoti citata:: citata;
naudoti syn::{parse_macro_input, DeriveInput, AttributeArgs};

#[proc_macro_attribute]
pubfnmano_atributo_makrokomandos(attr: TokenStream, elementas: TokenStream) -> TokenStream {
leisti args = parse_macro_input!(attr kaip AttributeArgs);
leisti input = parse_macro_input!(element kaip DeriveInput);
leisti pavadinimas = &input.ident;

leisti gen = citata! {
#įvestis
impl #vardas {
// čia pritaikytas elgesys
}
};

gen.into()
}

Makrokomandoje pateikiamas argumentų sąrašas ir struktūros apibrėžimas ir sugeneruoja modifikuotą struktūrą su apibrėžta pasirinktine elgsena.

Makrokomandoje kaip įvestis naudojami du argumentai: makrokomandai pritaikytas atributas (išanalizuotas su parse_macro_input! makrokomandą) ir elementą (išanalizuoti su parse_macro_input! makrokomandą). Makrokomandoje naudojama citata! makrokomandą kodui generuoti, įskaitant pradinį įvesties elementą ir papildomą impl blokas, apibrėžiantis pasirinktinį elgesį.

Galiausiai funkcija grąžina sugeneruotą kodą kaip a TokenStream su į () metodas.

Makro taisyklės

Makrokomandų taisyklės yra paprasčiausias ir lanksčiausias makrokomandų tipas. Makrokomandos taisyklės leidžia apibrėžti pasirinktinę sintaksę, kuri kompiliavimo metu išplečiama iki Rust kodo. Makrokomandų taisyklės apibrėžia pasirinktines makrokomandas, atitinkančias bet kokią rūdžių išraišką ar teiginį.

Naudosite makrokomandų taisykles, kad generuotumėte pagrindinį kodą, kad abstrahuotų žemo lygio detales.

Štai kaip galite apibrėžti ir naudoti makrokomandas savo „Rust“ programose:

makro_taisyklės! make_vector {
( $( $x: expr ),* ) => {
{
leistimut v = Sen::naujas();
$(
v.push($x);
)*
v
}
};
}

fnpagrindinis() {
leisti v = make_vector![1, 2, 3];
println!("{:?}", v); // spausdina "[1, 2, 3]"
}

Programa apibrėžia a make_vector! makrokomandą, kuri sukuria naują vektorių iš kableliais atskirtų išraiškų sąrašo pagrindinis funkcija.

Makrokomandoje šablono apibrėžimas atitinka makrokomandai perduodamus argumentus. The $( $x: galiojimo laikas ),* sintaksė atitinka visas kableliais atskirtas išraiškas, identifikuotas kaip x $.

The $( ) sintaksė išplėtimo kode kartojasi per kiekvieną išraišką argumentų sąraše, perduodama makrokomandai po baigiamasis skliaustas, nurodantis, kad iteracijos turėtų tęstis tol, kol makrokomandas apdoros visus posakius.

Efektyviai tvarkykite rūdžių projektus

Rūdžių makrokomandos pagerina kodo organizavimą, nes leidžia apibrėžti daugkartinio naudojimo kodo šablonus ir abstrakcijas. Makrokomandos gali padėti parašyti glaustesnį, išraiškingesnį kodą be pasikartojimų įvairiose projekto dalyse.

Be to, galite suskirstyti Rust programas į dėžes ir modulius, kad būtų galima geriau organizuoti kodą, pakartotinai naudoti ir sąveikauti su kitomis dėžėmis ir moduliais.