Rust
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.
Örnek çözümü göster
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());
}
Kendini test et
-
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
Cevabı göster
Derleyici onları önce derleyip kullanan crate'in derlemesi sırasında çalıştırır — Makro crate'i bir derleyici eklentisi gibi davranır; kendi tanımlandığı crate'in derlenmesi sırasında henüz hazır değildir.
-
Derive bildirimi
#[____(Merhaba)]
pub fn merhaba_turet(girdi: TokenStream) -> TokenStream {
todo!()
}
Cevabı göster
#[proc_macro_derive(Merhaba)]
pub fn merhaba_turet(girdi: TokenStream) -> TokenStream {
todo!()
}
-
Makro türü ve örnek
- derive
- #[derive(Serialize)]
- öznitelik
- #[tokio::main]
- fonksiyon benzeri
- sqlx::query!(..)
- bildirimsel
- macro_rules!
Sıradaki ders: derive makrosu