@@ -142,4 +142,139 @@ mod tests {
142142Örneğin Product, Customer, Order, Category ve benzeri entity nesnelerinin yer aldığı bir senaryoda her birisi için ayrı
143143ayrı struct geliştirmek yerine bir makro ile kod tekrarlarının önüne geçebilir, veri yapılarını basitçe
144144tanı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.
145+ halini inşa eder ve aynı zamanda new metodunu otomatik olarak implemente eder.
146+
147+ Sıradaki örnek makro bir kod bloğunun çalışma süresini ölçümlemekte kullanılır.
148+
149+ ``` rust
150+ macro_rules! wt {
151+ ($ block : block ) => {{
152+ let start = std :: time :: Instant :: now ();
153+ let result = $ block ;
154+ let duration = start . elapsed ();
155+ println! (" Total execution time: {:?}" , duration );
156+ result
157+ }};
158+ }
159+
160+ #[cfg(test)]
161+ mod tests {
162+ use super :: * ;
163+
164+ #[test]
165+ fn wt_test () {
166+ let sum = wt! ({
167+ let mut total = 0 ;
168+ for i in 1 .. 100 {
169+ total += i ;
170+ }
171+ total
172+ });
173+ assert_eq! (sum , 4950 );
174+ }
175+ }
176+ ```
177+
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.
183+
184+ ``` rust
185+ macro_rules! wt_with {
186+ ($ writer : expr , $ block : block ) => {{
187+ use std :: io :: Write ;
188+ let start = std :: time :: Instant :: now ();
189+ let result = $ block ;
190+ let duration = start . elapsed ();
191+ writeln! ($ writer , " Total execution time: {:?}" , duration ). unwrap ();
192+ result
193+ }};
194+ }
195+
196+ #[cfg(test)]
197+ mod tests {
198+ use super :: * ;
199+
200+ #[test]
201+ fn wt_with_test () {
202+ let sum = wt_with! (std :: io :: stdout (), {
203+ let mut total = 0 ;
204+ for i in 1 .. 100 {
205+ total += i ;
206+ }
207+ total
208+ });
209+ assert_eq! (sum , 4950 );
210+ }
211+ }
212+ ```
213+
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.
216+
217+ ![ Macro Test Result] ( MacroTestResult.png )
218+
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)_
222+
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.
225+
226+ ``` rust
227+ macro_rules! wt_with {
228+ ($ writer : expr , $ block : block ) => {{
229+ use std :: io :: Write ;
230+ let start = std :: time :: Instant :: now ();
231+ let result = $ block ;
232+ let duration = start . elapsed ();
233+ writeln! ($ writer , " Total execution time: {:?}" , duration ). unwrap ();
234+ result
235+ }};
236+ }
237+
238+ #[cfg(test)]
239+ mod tests {
240+ use super :: * ;
241+
242+ #[test]
243+ fn xml_test () {
244+ let data = xml! {
245+ game {
246+ id : 1 ,
247+ title : " Pacman 1983" ,
248+ rate : 9.6
249+ }
250+ };
251+ assert_eq! (
252+ data ,
253+ " <game id=\ " 1\ " title=\ " Pacman 1983\ " rate=\ " 9.6\ " />" . to_string ()
254+ );
255+ }
256+ }
257+ ```
258+
259+ ## Procedural Macros
260+
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+
265+ ![ Procedural Macro Types] ( ProceduralMacros.png )
266+
267+ Declarative makrolar ile aralarında bazı farklılıklar da vardır. Bunlar aşağıdaki tabloda özetlenmiştir.
268+
269+ | Özellik | Declarative Macros (` macro_rules! ` ) | Procedural Macros |
270+ | --------------------------| --------------------------------------------------------| ---------------------------------------------------------------|
271+ | ** Kullanım Zorluğu** | Basit, hızlı öğrenilir | Daha karmaşıktır ve öğrenmesi zaman alır |
272+ | ** Kod Genişletme** | Pattern matching ile belirgin genişletme sağlar | Kod analizi ile daha karmaşık işlemler yapılabilir |
273+ | ** Hata Mesajları** | Derleyici hatalarının anlaşılması zor olabilir | Daha karmaşık hatalar üretir |
274+ | ** Performans** | Çok hızlıdır, compile-time'da minimal etkisi vardır | Derleme süresinin artmasına neden olabilir |
275+ | ** 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 |
276+ | ** Kapsam** | Kod tekrarını azaltma veya basit DSL'ler için idealdir | Gelişmiş DSL'ler, derive ve attribute işlevleri için idealdir |
277+
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.
0 commit comments