CodeBlanks Logo Icon CodeBlanks

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.

Başlangıç kodu

main.rs
fn main() {
    // buraya yaz
}

Örnek çözüm

main.rs
#![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());
}

Beklenen çıktı

["ad", "yas"]

Soru ve cevaplar

Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.

1 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 Doğru cevap
  • Evet

Açıklama: Öğeyi değiştirmek isteyen makro bir öznitelik makrosu olmalıdır.

2 Alan adlarını metne çevir

Soru
&[$(____!($alan)),*]
Cevap
&[$(stringify!($alan)),*]

Açıklama: stringify! her alan adını &'static str olarak verir.

3 Araç ve görevi

Kavram Anlamı
syn Belirteçleri ayrıştırır
quote! Kod üretir
DeriveInput Struct/enum ağacı
#(#adlar),* quote! tekrarı

İleri seviye bölümündeki tüm dersler