derive makrosu
- Rust kursu
- İleri seviye
- Ders 49/81
- 4 dk
#[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
fn main() {
// buraya yaz
}Örnek çözüm
#![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
&[$(____!($alan)),*]
&[$(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ı |