Makrolar, başka kodlar yazan kodlar yazmanıza izin verir. Meta programlamanın garip ve güçlü dünyasını keşfedin.

Kod oluşturma, çoğu modern programlama dilinde bulacağınız bir özelliktir. Standart kodu ve kod tekrarını azaltmanıza, etki alanına özgü dilleri (DSL'ler) tanımlamanıza ve yeni sözdizimi uygulamanıza yardımcı olabilir.

Rust, daha karmaşık programlama için derleme zamanında kod oluşturmanıza izin veren güçlü bir makro sistemi sağlar.

Rust Makrolarına Giriş

Makrolar, kod yazan kod yazmak için kullanabileceğiniz bir tür meta programlamadır. Rust'ta makro, derleme zamanında başka kodlar üreten bir kod parçasıdır.

Rust makroları, yinelenen görevleri otomatikleştirmek için derleme zamanında başka kodlar oluşturan kodlar yazmanıza izin veren güçlü bir özelliktir. Rust'ın makroları, kod tekrarını azaltmaya ve kodun bakımını ve okunabilirliğini artırmaya yardımcı olur.

Basit kod parçacıklarından kitaplıklara ve çerçevelere kadar her şeyi oluşturmak için Makroları kullanabilirsiniz. Makrolar farklıdır Pas fonksiyonları çünkü çalışma zamanında veriler yerine kod üzerinde çalışırlar.

instagram viewer

Rust'ta Makro Tanımlama

ile makroları tanımlayacaksınız. macro_rules! makro. bu macro_rules! makro, girdi olarak bir model ve bir şablon alır. Rust, deseni giriş koduyla eşleştirir ve çıktı kodunu oluşturmak için şablonu kullanır.

Rust'ta Makroları şu şekilde tanımlayabilirsiniz:

macro_rules! Merhaba de {
() => {
yazdır!("Selam Dünya!");
};
}

fnana() {
Merhaba de!();
}

Kod bir tanımlar Merhaba de "Merhaba dünya!" yazdırmak için kod üreten makro. kod ile eşleşir () boş bir girdiye karşı sözdizimi ve yazdır! makro çıktı kodunu oluşturur.

İşte makroyu çalıştırmanın sonucu ana işlev:

Makrolar, oluşturulan kod için girdi bağımsız değişkenleri alabilir. İşte tek bir argüman alan ve bir mesaj yazdırmak için kod üreten bir Makro:

macro_rules! mesaj_say {
($mesaj: ifade) => {
yazdır!("{}", $mesaj);
};
}

bu say_message makro alır $mesaj kullanarak argümanı yazdırmak için kod üretir ve yazdır! makro. bu ifade sözdizimi, herhangi bir Rust ifadesine karşı argümanla eşleşir.

Rust Makro Türleri

Rust, üç tür makro sağlar. Makro türlerinin her biri belirli amaçlara hizmet eder ve bunların sözdizimi ve sınırlamaları vardır.

Prosedürel Makrolar

Prosedürel makrolar, en güçlü ve çok yönlü tür olarak kabul edilir. Prosedürel makrolar, aynı anda Rust kodu oluşturan özel sözdizimi tanımlamanıza izin verir. Özel türetilmiş makrolar, özel öznitelik benzeri makrolar ve özel işlev benzeri makrolar oluşturmak için Prosedürel makroları kullanabilirsiniz.

Yapıları ve enum özelliklerini otomatik olarak uygulamak için özel türetilmiş makroları kullanacaksınız. Serde gibi popüler paketler, Rust veri yapıları için serileştirme ve seriden çıkarma kodu oluşturmak üzere özel bir türetme makrosu kullanır.

Özel öznitelik benzeri makrolar, Rust koduna özel notlar eklemek için kullanışlıdır. Rocket web çerçevesi, yolları özlü ve okunaklı bir şekilde tanımlamak için özel bir öznitelik benzeri makro kullanır.

Yeni Rust ifadeleri veya ifadeleri tanımlamak için Özel işlev benzeri makroları kullanabilirsiniz. Lazy_static kasası, işlevi tanımlamak için özel bir işlev benzeri makro kullanır. tembel-başlatılmış statik değişkenler.

Özel bir türetme makrosu tanımlayan prosedürel bir makroyu şu şekilde tanımlayabilirsiniz:

kullanmak proc_macro:: TokenStream;
kullanmak alıntı:: alıntı;
kullanmak syn::{DeriveInput, parse_macro_input};

bu kullanmak yönergeler, bir Rust yordam makrosu yazmak için gerekli kasaları ve türleri içe aktarır.

#[proc_macro_derive (MyTrait)]
birahanefnmy_derive_macro(giriş: TokenStream) -> TokenStream {
izin vermek ast = parse_macro_input!(giriş gibi TüretGirdi);
izin vermek isim = &ast.ident;

izin vermek gen = alıntı! {
ima Özelliğim için #isim {
// uygulama burada
}
};

gen.into()
}

Program, bir yapı veya enum için bir özelliğin uygulanmasını oluşturan prosedürel bir makro tanımlar. Program, makroyu adıyla çağırır. Özelliğim struct veya enum'un türetme özelliğinde. Makro bir Jeton Akışı ile Soyut Sözdizimi Ağacına (AST) ayrıştırılan kodu içeren girdi olarak nesne parse_macro_input! makro.

bu isim değişken, türetilmiş yapı veya numaralandırma tanımlayıcısıdır, alıntı! Makro, uygulanmasını temsil eden yeni bir AST üretir. Özelliğim sonunda bir olarak döndürülen tür için Jeton Akışı ile içine yöntem.

Makroyu kullanmak için, makroyu bildirdiğiniz modülden içe aktarmanız gerekir:

// makroyu bir my_macro_module modülünde bildirdiğiniz varsayılarak

kullanmak my_macro_module:: my_derive_macro;

Makroyu kullanan yapıyı veya numaralandırmayı bildirirken, #[türet (MyTrait)] bildirimin en üstüne öznitelik.

#[türet (MyTrait)]
yapıYapım {
// buradaki alanlar
}

Özniteliğe sahip yapı bildirimi, aşağıdakilerin bir uygulamasına genişler: Özelliğim yapı için özellik:

ima Özelliğim için Yapım {
// uygulama burada
}

Uygulama, aşağıdaki yöntemleri kullanmanıza izin verir: Özelliğim özellik üzerinde Yapım örnekler.

Öznitelik Makroları

Nitelik makroları, yapılar, numaralandırmalar, işlevler ve modüller gibi Rust öğelerine uygulayabileceğiniz makrolardır. Nitelik makroları, bir bağımsız değişken listesi tarafından takip edilen bir öznitelik biçimini alır. Makro, Rust kodu oluşturmak için bağımsız değişkeni ayrıştırır.

Özel davranışlar ve açıklamaları kodunuza eklemek için özellik makrolarını kullanacaksınız.

İşte bir Rust yapısına özel bir nitelik ekleyen bir öznitelik makrosu:

// makro tanımı için modülleri içe aktarıyoruz
kullanmak proc_macro:: TokenStream;
kullanmak alıntı:: alıntı;
kullanmak syn::{parse_macro_input, DeriveInput, AttributeArgs};

#[proc_macro_attribute]
birahanefnmy_attribute_macro(öznitelik: TokenStream, öğe: TokenStream) -> TokenStream {
izin vermek args = parse_macro_input!(attr gibi AttributeArgs);
izin vermek girdi = parse_macro_input!(öğe gibi TüretGirdi);
izin vermek isim = &input.ident;

izin vermek gen = alıntı! {
#giriş
ima #isim {
// burada özel davranış
}
};

gen.into()
}

Makro bir argüman listesi alır ve yapı tanımı ve tanımlanmış özel davranışla değiştirilmiş bir yapı oluşturur.

Makro girdi olarak iki bağımsız değişken alır: makroya uygulanan öznitelik ( parse_macro_input! makro) ve öğe ( parse_macro_input! makro). Makro, alıntı! orijinal giriş öğesi ve ek bir öğe dahil olmak üzere kodu oluşturmak için makro ima özel davranışı tanımlayan blok.

Son olarak, işlev oluşturulan kodu bir Jeton Akışı ile içine() yöntem.

Makro Kuralları

Makro kuralları, makroların en basit ve esnek türüdür. Makro kuralları, derleme zamanında Rust koduna genişleyen özel sözdizimi tanımlamanıza olanak tanır. Makro kuralları, herhangi bir pas ifadesi veya ifadesiyle eşleşen özel makroları tanımlar.

Alt düzey ayrıntıları soyutlamak için standart kod oluşturmak için makro kurallarını kullanacaksınız.

Rust programlarınızda makro kurallarını şu şekilde tanımlayabilir ve kullanabilirsiniz:

macro_rules! make_vector {
( $( $x: ifade ),* ) => {
{
izin vermekmut v = Vec::yeni();
$(
v.push($x);
)*
v
}
};
}

fnana() {
izin vermek v = make_vector![1, 2, 3];
yazdır!("{:?}", v); // "[1, 2, 3]" yazdırır
}

Program tanımlar make_vector! virgülle ayrılmış ifadeler listesinden yeni bir vektör oluşturan bir makro. ana işlev.

Makronun içinde, model tanımı, makroya iletilen bağımsız değişkenlerle eşleşir. bu $( $x: ifade ),* sözdizimi, olarak tanımlanan tüm virgülle ayrılmış ifadelerle eşleşir $x.

bu $( ) genişletme kodundaki sözdizimi, makroya iletilen bağımsız değişkenler listesindeki her ifade üzerinde yinelenir. kapanış parantezi, yinelemelerin makro tüm öğeleri işleyene kadar devam etmesi gerektiğini belirtir. ifade.

Rust Projelerinizi Verimli Bir Şekilde Düzenleyin

Rust makroları, yeniden kullanılabilir kod kalıpları ve soyutlamalar tanımlamanıza izin vererek kod organizasyonunu geliştirir. Makrolar, çeşitli proje bölümlerinde tekrarlar olmadan daha özlü, anlamlı kodlar yazmanıza yardımcı olabilir.

Ayrıca, daha iyi kod organizasyonu, yeniden kullanılabilirlik ve diğer kasalar ve modüllerle birlikte çalışma için Rust programlarını kasalar ve modüller halinde düzenleyebilirsiniz.