Rust
derive makrosu
#[proc_macro_derive] ile derive makrosu yazarsın.
derive makrosu
Gerçek bir derive makrosu struct'ı ayrıştırır ve alanlarına göre kod üretir. syn ayrıştırır, quote üretir:
#[proc_macro_derive(Alanlar)]
pub fn alanlar(girdi: TokenStream) -> TokenStream {
let ast = syn::parse_macro_input!(girdi as syn::DeriveInput);
let ad = &ast.ident;
let syn::Data::Struct(veri) = &ast.data else { panic!("yalnızca struct") };
let adlar = veri.fields.iter().map(|f| f.ident.as_ref().unwrap().to_string());
quote::quote! {
impl #ad {
fn alanlar() -> &'static [&'static str] { &[#(#adlar),*] }
}
}.into()
}
quote! içinde #ad bir değişkeni yerleştirir, #(..),* tekrar eder; macro_rules! sözdizimine benzer.
macro_rules! ile aynı fikir
Struct tanımını makroya bütün olarak verirsek, alanları macro_rules! ile de okuyabiliriz:
macro_rules! alanli_struct {
(struct $ad:ident { $($alan:ident : $tur:ty),* $(,)? }) => {
struct $ad { $($alan: $tur),* }
impl $ad {
fn alanlar() -> &'static [&'static str] {
&[$(stringify!($alan)),*]
}
}
};
}
Sınırları: genericler, öznitelikler, görünürlük gibi her varyasyon için kalıp yazmak gerekir; syn bunların hepsini ayrıştırır.
Uygulama Alan listesi
Yukarıdaki alanli_struct! makrosunu yaz ve struct Kisi { ad: String, yas: u32 } tanımını onunla üret. Kisi::alanlar() sonucunu {:?} ile yazdır.
Örnek çözümü göster
#![allow(dead_code)]
macro_rules! alanli_struct {
(struct $ad:ident { $($alan:ident : $tur:ty),* $(,)? }) => {
struct $ad {
$($alan: $tur),*
}
impl $ad {
fn alanlar() -> &'static [&'static str] {
&[$(stringify!($alan)),*]
}
}
};
}
alanli_struct!(struct Kisi { ad: String, yas: u32 });
fn main() {
println!("{:?}", Kisi::alanlar());
}
Kendini test et
-
Derive makrosu girdi struct'ını değiştirebilir mi?
- Yalnızca alanları
- Yalnızca adı
- Hayır; yalnızca yeni öğeler ekler, struct olduğu gibi kalır
- Evet
Cevabı göster
Hayır; yalnızca yeni öğeler ekler, struct olduğu gibi kalır — Öğeyi değiştirmek isteyen makro bir öznitelik makrosu olmalıdır.
-
Alan adlarını metne çevir
&[$(____!($alan)),*]
Cevabı göster
&[$(stringify!($alan)),*]
-
Araç ve görevi
- syn
- Belirteçleri ayrıştırır
- quote!
- Kod üretir
- DeriveInput
- Struct/enum ağacı
- #(#adlar),*
- quote! tekrarı
Sıradaki ders: attribute makrosu