CodeBlanks Logo Icon CodeBlanks

proc_macro cratei

proc_macro crate'ini ve temel API'sini tanırsın.

proc_macro crate'i

Prosedürel makrolar, derleme anında çalışan sıradan Rust fonksiyonlarıdır: bir TokenStream alır, yeni bir TokenStream döndürürler. Ayrı bir crate'te, proc-macro = true ile tanımlanmaları gerekir:

# Cargo.toml (makro crate'i)
[lib]
proc-macro = true

// src/lib.rs
use proc_macro::TokenStream;

#[proc_macro_derive(Merhaba)]
pub fn merhaba_turet(girdi: TokenStream) -> TokenStream {
    // girdi: struct tanımının belirteçleri
    // çıktı: üretilecek impl bloğu
    todo!()
}

Üç türü vardır: #[derive(..)] makroları, öznitelik makroları (#[route(..)]) ve fonksiyon benzeri makrolar (sql!(..)).

Ne üretir?

#[derive(Merhaba)] struct Kedi; için makronun üreteceği kod, elle yazacağın impl'in aynısıdır. Aynı fikri tek dosyada macro_rules! ile görebiliriz:

trait Merhaba {
    fn merhaba() -> String;
}

macro_rules! merhaba_turet {
    ($t:ident) => {
        impl Merhaba for $t {
            fn merhaba() -> String {
                format!("Merhaba, ben {}", stringify!($t))
            }
        }
    };
}

struct Kedi;
merhaba_turet!(Kedi);

Fark: prosedürel makro struct tanımını kendisi okur; burada adı biz veriyoruz.

Uygulama Derive'ın ürettiği

Yukarıdaki Merhaba trait'ini ve merhaba_turet! makrosunu yaz. struct Kedi; ve struct Kopek; için makroyu uygula; iki türün merhaba() sonucunu ayrı satırlara yazdır.

Başlangıç kodu

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

Örnek çözüm

main.rs
trait Merhaba {
    fn merhaba() -> String;
}

macro_rules! merhaba_turet {
    ($t:ident) => {
        impl Merhaba for $t {
            fn merhaba() -> String {
                format!("Merhaba, ben {}", stringify!($t))
            }
        }
    };
}

struct Kedi;
struct Kopek;
merhaba_turet!(Kedi);
merhaba_turet!(Kopek);

fn main() {
    println!("{}", Kedi::merhaba());
    println!("{}", Kopek::merhaba());
}

Beklenen çıktı

Merhaba, ben Kedi
Merhaba, ben Kopek

Soru ve cevaplar

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

1 Prosedürel makrolar neden ayrı bir crate'te olmalıdır?

  • Güvenlik kuralı
  • Daha hızlı oldukları için
  • Gerekmez
  • Derleyici onları önce derleyip kullanan crate'in derlemesi sırasında çalıştırır Doğru cevap

Açıklama: Makro crate'i bir derleyici eklentisi gibi davranır; kendi tanımlandığı crate'in derlenmesi sırasında henüz hazır değildir.

2 Derive bildirimi

Soru
#[____(Merhaba)]
pub fn merhaba_turet(girdi: TokenStream) -> TokenStream {
    todo!()
}
Cevap
#[proc_macro_derive(Merhaba)]
pub fn merhaba_turet(girdi: TokenStream) -> TokenStream {
    todo!()
}

Açıklama: #[proc_macro_derive(Ad)] bir derive makrosu tanımlar.

3 Makro türü ve örnek

Kavram Anlamı
derive #[derive(Serialize)]
öznitelik #[tokio::main]
fonksiyon benzeri sqlx::query!(..)
bildirimsel macro_rules!

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