Skip to content

Commit 9f4872f

Browse files
committed
Updated readme document
1 parent 5e4024b commit 9f4872f

File tree

1 file changed

+62
-55
lines changed

1 file changed

+62
-55
lines changed

Lesson_13/README.md

Lines changed: 62 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
# Ders 13: Macros
22

3-
Makrolar meta programlamanın temel unsurlarındadır. Meta programlama kod yazan kodlar oluşturulmasını benimseyen bir
4-
yaklaşımdır. Makroları kullanarak kod tekrarını azaltabilir ve daha okunabilir kodların oluşturulmasını sağlayabiliriz.
5-
Makrolar ile delerme zamanında kaynak kod üzerinde manipülasyon da yapılabilir. Ayrıca struct, enum, fn gibi yapıların
6-
derleme zamanında analiz edilip yeni kodların üretilmesini de sağlayabiliriz. Bugüne kadarki örneklerimizde bir çok
7-
makro kullandık. println!, write!, vec! gibi sonu ! ile biten enstrümanlar aslında birer makrodur. Makroları Declarative
8-
_(Bildirime dayalı)_ ve Procedural _(Yönergelere dayalı)_ olmak üzere iki ana kategoriye ayırabiliriz.
3+
Makrolar kod yazan kodlar oluşturulmasını benimseyen bir meta programlama yaklaşımdır. Makroları kullanarak kod
4+
tekrarlarını azaltabilir, daha okunabilir kodlar oluşturulabilir, delerme zamanında kaynak kod üzerinde değişikliler
5+
yapılabilir. Ayrıca **struct**, **enum**, **fn** gibi yapıların derleme zamanında analiz edilip yeni kodların üretilmesi
6+
de sağlanabilir. Önceki örneklerde bir çok makro kullanılmıştır. **println!**, **write!**, **vec!** gibi sonu **!** ile
7+
biten enstrümanlar aslında birer makrodur. Makrolar Declarative _(Bildirime dayalı)_ ve Procedural _(Yönergelere
8+
dayalı)_ olmak üzere iki ana kategoriye ayrılır.
99

1010
## Hello Macro _(Declarative)_
1111

12-
Makrolar belli bir fonksiyonelliğin farklı türevlerinin yazmaktan kaçınmamızı da sağlar. Aşağıdaki basit fonksiyonu göz
12+
Makrolar ile belli bir fonksiyonelliğin farklı türevlerinin yazmak zorunda kalmayız. Aşağıdaki basit fonksiyonu göz
1313
önüne alalım.
1414

1515
```rust
@@ -32,10 +32,9 @@ mod tests {
3232
}
3333
```
3434

35-
max_of_two fonksiyonu iki integer değerden hangisi büyükse onu geriye döndürmek amacıyla tasarlanmıştır. Ancak n adet
36-
sayının birbiriyle karşılaştırılmasını istediğimiz bir durumda ne yaparız? Bu genellikle yeni bir fonksiyon yazılmasını
37-
gerektirecektir. Bunun yerine bir makro hazırlayıp, sum_of fonksiyon bloğunun gelen koşullara göre üretilmesini de
38-
sağlayabiliriz.
35+
**max_of_two** fonksiyonu iki tam sayı değerden hangisi büyükse onu geriye döndürmek amacıyla tasarlanmıştır. Ancak n
36+
adet sayının birbiriyle karşılaştırılması istendiğinde fonksiyonun farkı bir versiyonunun yazılması gerekir. Bunun
37+
yerine bir makro hazırlayıp, **max_of** fonksiyon bloğunun gelen koşullara göre üretilmesini sağlanabilir.
3938

4039
```rust
4140
macro_rules! max_of {
@@ -66,21 +65,22 @@ mod tests {
6665
}
6766
```
6867

69-
Declarative yani bildirime dayalı makrolar yazmak için macro_rules isimli başka bir makro kullanılır. Kendi yazdığımız
70-
makrolar dahil isimlendirmelerde fonksiyon adı ! işareti ile sonlandırılır. Örnekte bazı özel kalıpları kullanılmıştır.
68+
Declarative yani bildirime dayalı makrolar yazmak için **macro_rules** isimli başka bir makro kullanılır. Kendi
69+
yazdığımız makrolar dahil isimlendirmelerde fonksiyon adı **!** işareti ile sonlandırılır. Örnekte bazı özel kalıplar
70+
kullanılmıştır.
7171

72-
- ($x:expr) => { $x } : Tek bir argüman ile çalışılacağını belirtir. expr ile bir expression türü ifade edilir.
72+
- ($x:expr) => { $x } : Tek bir argüman ile çalışılacağını belirtir. **expr** ile bir **expression** türü ifade edilir.
7373
Dolayısıyla makronun uygulandığı yapıda tek bir sayısal ifade varsa doğrudan döndüren bir kod bloğu üretilecektir.
74-
- ($x:expr, $y:expr) => { ... } : Bu kısımda ise iki argümanla eşleşilen durumu ele alır. Burada if kullanılan bir kod
74+
- ($x:expr, $y:expr) => { ... } : Bu kısımda ise iki argümanla eşleşilen durum ele alınır. **if** kullanılan bir kod
7575
bloğunun üretimi sağlanır.
7676
- ($x:expr, $($y:expr),+) => { ... } : Bu kalıpsa iki veya daha fazla argüman için geçerlidir. İkinci söz diziminde yer
77-
alan + operaötörü en az bir veya daha fazla anlamındadır. Bu durumla karşılaşılması halinde recursive olarak kendisini
78-
çağıran bir fonksiyon kodu üretilecektir.
77+
alan **+** operaötörü en az bir veya daha fazla anlamına gelir. Bu durumla karşılaşılması halinde **recursive** olarak
78+
kendisini çağıran bir fonksiyon kodu üretilir.
7979

8080
## MetaSyntactic Variables
8181

82-
Makrolarda ifadeleri analiz etmek ve eşleşmeleri yakalamak için token'lar kullanılır. Bunlardan en çok kullanılanlar
83-
aşağıdaki tabloda belirtilmektedir.
82+
Makrolarda ifadeleri analiz etmek ve eşleşmeleri yakalamak için **token**'lar kullanılır. En sık kullanılan token
83+
değerleri aşağıdaki tabloda özetlenmiştir.
8484

8585
| Token | Açıklama | Örnek |
8686
|-----------|-----------------------------------------------------------------------|---------------------------------------------------|
@@ -97,8 +97,8 @@ aşağıdaki tabloda belirtilmektedir.
9797

9898
## Örnekler
9999

100-
Aşağıdaki kod parçalarında farklı senaryoların ele alındığı procedural makrolar yer almaktadır. İlk örnek bir model
101-
nesnesi için gerekli struct'ı kolayca oluşturmak için kullanılır.
100+
Aşağıdaki kod parçalarında farklı senaryoların ele alındığı **procedural** makro örnekleri yer almaktadır. İlk örnek bir
101+
model nesnesi için gerekli struct'ın kolayca oluşturulması için kullanılır.
102102

103103
```rust
104104
macro_rules! crud {
@@ -139,12 +139,13 @@ mod tests {
139139
}
140140
```
141141

142-
Örneğin Product, Customer, Order, Category ve benzeri entity nesnelerinin yer aldığı bir senaryoda her birisi için ayrı
143-
ayrı struct geliştirmek yerine bir makro ile kod tekrarlarının önüne geçebilir, veri yapılarını basitçe
144-
tanımlayabiliriz. crud isimli makro argüman olarak gelen identifier ve type bilgilerini kullanarak struct'ın temel
145-
halini inşa eder ve aynı zamanda new metodunu otomatik olarak implemente eder.
142+
Örneğin **Product**, **Customer**, **Order**, **Category** ve benzeri entity nesnelerinin yer aldığı bir senaryoda her
143+
biri için ayrı ayrı **struct** yazmak yerine bir makro ile kod tekrarlarının önüne geçebilir. **crud** isimli makro
144+
argüman olarak gelen **identifier** ve **type** bilgilerini kullanarak **struct**'ın temel halini inşa eder ve aynı
145+
zamanda **new** metodunu da otomatik olarak implemente eder. Bu senaryo veri model nesnelerinin farklı kaynaklardan
146+
geldiği _(örneğin metin tabanlı dosyalar)_ durumlarda kullanışlı olabilir. Bunu araştırıp deneyiniz.
146147

147-
Sıradaki örnek makro bir kod bloğunun çalışma süresini ölçümlemekte kullanılır.
148+
Sıradaki makro bir kod bloğunun çalışma süresini ölçümlemek için kullanılır.
148149

149150
```rust
150151
macro_rules! wt {
@@ -175,11 +176,11 @@ mod tests {
175176
}
176177
```
177178

178-
Örnekteki makro $block ifadesi ile aslında bir kod bloğunu ele alır. Bu bloğun öncesine bir sayaç yerleştirir ve son
179-
olarak da çıktıyı terminal ekranına basar. println! kullanımı demo ve öğrenim senaryoları için yeterlidir ancak makronun
180-
bir kütüphane üzerinden kullanıma açışması söz konusu olacaksa terminal bağımsız çalışan kısacası stdout üzerinden çıktı
181-
veren bir hale getirilmesi daha doğru olur. Bu, makronun biraz daha farklı yazılmasını gerektirebilir. Aşağıdaki kod
182-
parçasında bu durum ele alınmaktadır.
179+
Örnekteki makro **$block** ifadesi ile aslında bir kod bloğunu ele alır. Bu bloğun öncesine bir sayaç yerleştirir ve son
180+
olarak da çıktıyı terminal ekranına basar. **println!** kullanımı demo ve öğrenim senaryoları için yeterlidir ancak
181+
makronun bir kütüphane üzerinden kullanıma açışması söz konusu ise terminal bağımsız çalışan kısacası **stdout**
182+
üzerinden çıktı veren bir hale getirilmesi daha doğrudur. Bu, makronun biraz daha farklı yazılmasını gerektirebilir.
183+
Aşağıdaki kod parçasında bu durum ele alınmaktadır.
183184

184185
```rust
185186
macro_rules! wt_with {
@@ -211,17 +212,19 @@ mod tests {
211212
}
212213
```
213214

214-
Makroya parametre atandığına dikkat edilmelidir. Bu bir nevi writeln! çağrısının hangi ortama yapılacağının
215-
soyutlanmasıdır. Test metodundaki gibi stdout verilmesi, bilginin terminaldeki test çıktısına yansıtılmasını sağlar.
215+
Makroya parametre atandığına dikkat edilmelidir. Bu, bir nevi **writeln!** çağrısının hangi ortama yapılacağının
216+
soyutlanmasıdır. **Test** metodundaki gibi **stdout** verilmesi, bilginin terminaldeki test çıktısına yansıtılmasını
217+
sağlar.
216218

217219
![Macro Test Result](MacroTestResult.png)
218220

219-
Dolayısıyla çıktının writeln! makrosunu kullanabilen bir logger'a, network stream'a veya bir veritabanına aktarılması da
220-
mümkündür. _(Bu durum C#, Java gibi dillerdeki bileşen bağımlılıklarının metotlar üzerinden enjekte edilerek
221-
kullanılmasına da benzetilebilir. Daha detaylı bilgi için Dependency Injection konusuna bakılabilir)_
221+
Dolayısıyla çıktının **writeln!** makrosunu kullanabilen bir **logger** nesnesine, **network** stream'a veya bir
222+
veritabanına aktarılması da mümkündür. _(Bu durum C#, Java gibi dillerdeki bileşen bağımlılıklarının metotlar üzerinden
223+
enjekte edilerek kullanılmasına da benzetilebilir. Daha detaylı bilgi için **Dependency Injection** konusuna
224+
bakılabilir)_
222225

223-
Devam eden örnekte ise kod bloğu içerisinde gönderilen bir veri yapısının XML çıktısını hazırlayan kodların yazıldığı
224-
bir makro söz konusudur.
226+
Devam eden örnekte ise kod bloğu içerisinde gönderilen bir veri yapısının **XML** çıktısını hazırlayan kodların
227+
yazıldığı bir makro söz konusudur.
225228

226229
```rust
227230
macro_rules! wt_with {
@@ -258,13 +261,15 @@ mod tests {
258261

259262
## Procedural Macros
260263

261-
Procedural makrolar bir Rust kodundan yararlanarak başka bir rust kodu üretilmesinde sıklıkla kullanılır. TokenStream
262-
girdileri ile çalışır. Temelde üç türü vardır. Derive direktifi ile kullanılanlar, attribute olarak kullanılanlar ve
263-
fonksiyon stilinde kullanılanlar.
264+
**Procedural** makrolar bir Rust kodundan yararlanarak başka bir rust kodu üretilmesinde sıklıkla kullanılır.
265+
**TokenStream** girdileri ile çalışır. Bu nedenle dilin genel semantik yapısına ve abstract syntax tree gibi kavramlara
266+
aşina olmakta yarar vardır. Temelde üç tür **procedural** makro vardır. **Derive** direktifi ile kullanılanlar,
267+
**attribute** şeklinde tasarlananlar ve fonksiyon stilinde yazılanlar.
264268

265269
![Procedural Macro Types](ProceduralMacros.png)
266270

267-
Declarative makrolar ile aralarında bazı farklılıklar da vardır. Bunlar aşağıdaki tabloda özetlenmiştir.
271+
**Procedural** ve **Declarative** makrolar arasında bazı temel farklılıklar vardır. Bunlar aşağıdaki tabloda
272+
özetlenmiştir.
268273

269274
| Özellik | Declarative Macros (`macro_rules!`) | Procedural Macros |
270275
|--------------------------|--------------------------------------------------------|---------------------------------------------------------------|
@@ -275,9 +280,9 @@ Declarative makrolar ile aralarında bazı farklılıklar da vardır. Bunlar aş
275280
| **Karmaşıklık Yönetimi** | Büyük ve karmaşık işleri yönetmek zordur | Büyük projelerde karmaşıklığın daha iyi yönetilmesini sağlar |
276281
| **Kapsam** | Kod tekrarını azaltma veya basit DSL'ler için idealdir | Gelişmiş DSL'ler, derive ve attribute işlevleri için idealdir |
277282

278-
Procedural Macro'lar, proc-macro crate olarak adlandırılan ayrı bir kütüphanede yazılırlar. Rust söz dizimi üzerinde
279-
TokenStream kullanılarak işlem yapılması bazı durumlarda zorlayıcı olabilir. syn ve quote gibi küfeler genellikle işi
280-
kolaylaştıran enstrümanlar içerirler.
283+
Procedural makrolar, **proc-macro** crate olarak adlandırılan ayrı bir kütüphane formatında yazılırlar. Rust söz dizimi
284+
üzerinde **TokenStream** kullanılarak işlem yapılması bazı durumlarda zorlayıcı olabilir. **syn** ve **quote** gibi
285+
küfeler genellikle işi kolaylaştıran enstrümanlar içerirler.
281286

282287
## Örnek Procedural Macro
283288

@@ -291,14 +296,15 @@ cargo add quote
291296
cargo add syn -F full
292297
```
293298

294-
Ardından toml dosyasında bu küfenin bir procedural macro olarak ele alınması gerektiği bildirilir.
299+
Ardından **toml** dosyasında bu küfenin procedural bir macro kütüphanesi olarak ele alınması gerektiği belirtilir.
295300

296301
```toml
297302
[lib]
298303
proc-macro = true
299304
```
300305

301-
Aşağıda kodun çalışma zamanının ölçen bir işlevselliğin procedural macro olarak nasıl yazılabileceği örneklenmektedir.
306+
Aşağıda kodun çalışma zamanını ölçen bir işlevselliğin **procedural macro** olarak nasıl yazılabileceği
307+
örneklenmektedir.
302308

303309
```rust
304310
extern crate proc_macro;
@@ -325,15 +331,16 @@ pub fn work_time_effort(_attr: TokenStream, item: TokenStream) -> TokenStream {
325331
}
326332
```
327333

328-
İlgili makro parametre olarak TokenStream'ler alır. Özellikle item değişkeni kod içerisinde kullanılır. item değişkeni
329-
ile gelen TokenStream parse_macro_input! makrosu kullanılarak içeriği ele alınabilir bir türe dönüştürülür. Buradan
330-
hareketle makronun uygulandığı metodun adı ve gövdesi yakalanbilir.
334+
İlgili makro parametre olarak **TokenStream**'ler alır. Özellikle **item** değişkeni kod içerisinde kullanılır. item
335+
değişkeni ile gelen **TokenStream**, **parse_macro_input!** makrosu kullanılarak içeriği ele alınabilir bir türe
336+
dönüştürülür. Bir başka deyişle stream üzerinden gelen kod içerisindeki unsurlar özellik şeklinde ele alınabilir hale
337+
gelir. Buradan hareketle makronun uygulandığı metodun adı ve gövdesi yakalanmaktadır.
331338

332-
İlerleyen adımda quote! makrosu ile yeni bir fonksiyon hazırlanır. Dikkat edileceği üzere gelen fonksiyon bloğunun
339+
İlerleyen adımda **quote!** makrosu ile yeni bir fonksiyon hazırlanır. Dikkat edileceği üzere gelen fonksiyon bloğunun
333340
öncesine ve sonrasına yeni kod parçaları eklenmektedir. Makro çıktı olarak üretilen yeni kod parçasını yine bir
334-
TokenStream olarak dışarı verir.
341+
**TokenStream** olarak dışarı verir.
335342

336-
Bu makro herhangibir metot için aşağıdaki gibi kullanılabilir.
343+
Bu makro herhangi bir metot için aşağıdaki gibi kullanılabilir.
337344

338345
```rust
339346
mod samples;
@@ -354,8 +361,8 @@ fn main() {
354361
}
355362
```
356363

357-
Bir procedural macro küfesini kullanmak için ilgili projeye dependency olarak bildirilmesi gerekir. Bunun için toml
358-
dosyasındaki ilgili kısım değiştirilmelidir. Örneğin,
364+
Bir procedural macro küfesini kullanmak için ilgili projeye **dependency** olarak bildirilmesi gerekir. Bunun için makro
365+
kütüphanesini kullanacak projenin **toml** dosyasında aşağıdaki gibi bir değişiklik yapılmalıdır.
359366

360367
```toml
361368
[dependencies]

0 commit comments

Comments
 (0)