{"id":16428505,"url":"https://github.com/buraksenyurt/silver-eureka","last_synced_at":"2025-10-26T23:31:02.319Z","repository":{"id":57626439,"uuid":"415405969","full_name":"buraksenyurt/silver-eureka","owner":"buraksenyurt","description":"Bir süre önce aldığım \"Rust Programming Cookbook\" kitabını çalışmak için açtığım repo. Örnekleri adım adım yapmayı ve rust bilgimi tazeleyip eksikleri görmeyi planlıyorum.","archived":false,"fork":false,"pushed_at":"2021-12-02T13:39:36.000Z","size":4059,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-08T11:48:25.895Z","etag":null,"topics":["learning","rust","rust-lang","self-learning"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/buraksenyurt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-10-09T19:40:40.000Z","updated_at":"2024-03-28T05:22:23.000Z","dependencies_parsed_at":"2022-08-31T09:11:41.404Z","dependency_job_id":null,"html_url":"https://github.com/buraksenyurt/silver-eureka","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buraksenyurt%2Fsilver-eureka","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buraksenyurt%2Fsilver-eureka/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buraksenyurt%2Fsilver-eureka/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buraksenyurt%2Fsilver-eureka/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/buraksenyurt","download_url":"https://codeload.github.com/buraksenyurt/silver-eureka/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238408712,"owners_count":19467168,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["learning","rust","rust-lang","self-learning"],"created_at":"2024-10-11T08:17:14.396Z","updated_at":"2025-10-26T23:30:56.801Z","avatar_url":"https://github.com/buraksenyurt.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Rust Programming Cookbook Çalışma Alanım\n\nBir süre önce aldığım [Rust Programming Cookbook](https://amzn.to/3Bw5ysw) kitabını çalışmak için açtığım bir çalışma alanıdır. İş hayatında sürekli .Net platformunda ve C# ile kod geliştirdiğimden Rust ile yazma alışkanlığım son derece zayıf. Önceden çalıştığım pek çok konuyu unutmuş durumdayım. Kitabın anlattığı kodları copy-paste yapmadan bakarak yazmayı, bu sayede parmaklarımı rust sözdizimine alıştırmayı ve kısa notlar tutarak önceden baktığım konuları biraz daha özümsemeyi amaçlıyorum.\n\n## Ön Hazırlıklar\n\nHer şeyden önce çalışmalarımı Windows 10 tabanlı bir sistemde yapmaktayım. Rust'ın kurulumu için kitabın da önerdiği üzere [https://rustup.rs](https://rustup.rs) adresine gidip indirdiğim installer'ı çalıştırdım. Kurulumun başarılı olup olmadığını görmek için komut satırından _rustc --version_ komutunu çalıştırdım.\n\n![./assets/screenshot_01.png](./assets/screenshot_01.png)\n\nGeliştirmeler için Visual Studio Code kullanacağım. Rust eklentisi için command-line interface'i açıp(Ctrl+P) sonrasında _ext install rust-lang.rust_ komutunu çalıştırmak yeterli.\n\n![./assets/screenshot_02.png](./assets/screenshot_02.png)\n\n## day01 - Başlangıç Adımları\n\nKitabın birinci bölümüne ait çalışmalar.\n\n### Komut Satırı ile Temel İşlemler\n\n```bash\n# Terminalden aşağıdaki komut çalıştılır ve ilk proje oluşturulur\ncargo new wonderful-world\n\n# Örneği çalıştırmak içinse (Tabi kodlama yaptıktan sonra :) )\ncd wonderful-world\ncargo run\n```\n\n![./assets/screenshot_03.png](./assets/screenshot_03.png)\n\n### Veri Türleri\n\n```bash\n# Bu sefer bir kütüphane oluşturuyoruz\ncargo new data-types --lib\ncd data-types\n# test fonksiyonları üstünden ilerliyoruz\ncargo test\n```\n\n![./assets/screenshot_04.png](./assets/screenshot_04.png)\n\n### Karar Yapıları ve Döngüler\n\n```bash\ncargo new flows --lib\ncd flows\ncargo test\n```\n\n![./assets/screenshot_05.png](./assets/screenshot_05.png)\n\n### Sandık(Crate) ile Çalışmak\n\nFonksiyon içeren bir modül oluşturup diğerinden kullanılması. Tipik yürütücü uygulama ve referans olarak kullandığı kütüphane senaryosu.\n\n```bash\n# Kütüphane oluşturulması\ncargo new rust-matlib --lib\n\n# ana uygulamanın oluşturulması\ncargo new calculator\n\n# ana uygulamada bir modül oluşturulması(klasör içinde mod isimli rust dosyası da oluşturulur)\ncd calculator\nmkdir basic\ncd basic\ntouch mod.rs\n\n# rust-mathlib testlerini çalıştırmak için, o klasörde,\ncargo test\n\n# calculator'u çalıştırmak için o klasörde\ncargo run\n```\n\ncalculator'un rust-matlib'i kullanabilmesi için toml dosyasında gerekli dependency eklenmiştir. Ayrıca calculator projesinde basic isimli bir klasör vardır. Burası basic isimli modülü temsil eder.\n\n![./assets/screenshot_06.png](./assets/screenshot_06.png)\n\n### Dokümantasyon Eklenmesi\n\nÇok basit anlamda markdown stili kullanılarak yardım dokümanı oluşturulabilyor. /// veya ///! ile bu işlemler gerçekleştirilebiliyor.\n\n```bash\ncd rust-matlib\ncargo doc\n```\n\nSonrasında silver-eureka/day01/rust-matlib/target/doc/rust_matlib/index.html sayfası açılarak Help içeriği görülebilir.\n\n![./assets/screenshot_07.png](./assets/screenshot_07.png)\n\n### Trait Kullanımı\n\nAbstract sınıflara benzetebileceğimiz trait enstrümanı ile aynı davranışı birden fazla struct'ın kullanması mümkün olabilir. Örnekte bir key:value çiftinin okunması, yazılması ile ilgili davranış tanımlamaları yapılmakta ve uygulanmakta.\n\n```bash\ncargo new traits --lib\n```\n\n![./assets/screenshot_08.png](./assets/screenshot_08.png)\n\n### Sequence Tipleri\n\nTek bir veri türünden oluşabilen ve boyutu değiştirilemeyen dizi, farklı türden veriler barındırabilen ama boyutu değiştirilemeyen Tuple ve generic tipleri kullanıp dinamik olarak boyutu ayarlanabilen Vector tiplerinin kullanım örnekleri.\n\n```bash\ncargo new sequences --lib\ncd sequences\ncargo test\n```\n\n![./assets/screenshot_09.png](./assets/screenshot_09.png)\n\n## day02 - Biraz Daha\n\nKitabın ikinci bölümüne ait çalışmalar.\n\n### enum Kullanımı\n\nPek çok dilde olduğu gibi Rust tarafında da sayıları anlamlı şekilde isimlendirmek için enum türünden faydalanılıyor ama fazlası da olabilir. Enum sabiti özelliklerinde farklı türleri kullanmak, enum sabitine fonksiyonellik kazandırmak, pattern matching ifadelerinde ele almak vs\n\n```bash\nmkdir day02\ncd day02\ncargo new using_enums --lib\ncd using_enums\ncargo test\n```\n![./assets/screenshot_10.png](./assets/screenshot_10.png)\n\n### Null Olmayan Güzel Bir Dünya\n\nRust dilinde fonksiyonel dillerin bir geleneği olarak her girdinin karşılığında anlamlı bir çıktının üretilmesi amaçlanır. null tipi yoktur. Bunun yerine Option\u003c T\u003e ve Result\u003cT,E\u003e tipleri kullanılır. Bir hata oluşma ihtimali varsa Result enum sabiti tercih edilir. Bu enum türleri aşağıdaki gibidir.\n\n```rust\npub enum Option\u003cT\u003e {\n    Some(T),\n    None,\n}\n\npub enum Result\u003cT,E\u003e{\n    Ok(T),\n    Err(E),\n}\n```\n\nÖrnekte Option tipinin farklı kullanım şekilleri ele alınmakta.\n\n```bash\ncargo new no_null --lib\ncd no_null\ncargo test\n```\n\n![./assets/screenshot_11.png](./assets/screenshot_11.png)\n\n### Pattern Matching için Verimli Kullanım Senaryoları\n\nPattern matching kabiliyetinin enum'larla sınırlı olmadığına dair örnek kodlar yer alıyor. _(literal, tuple, String(heap allocation sebebiyle diğer literallerden farklı ama kullanım şekli aynı) türleri ile kullanım, destructuring ve guard mevzusu)_\n\n```bash\ncargo new amazing_pattern_matching\ncd amazing_pattern_matching\ncargo run\n```\n\n![./assets/screenshot_12.png](./assets/screenshot_12.png)\n\n### Basit Bir Linked List Oluşturmak\n\nKitabın bir sonraki örneğinde Iterator deseni kullanılan bir örnek yer alıyor. Ancak örnek içerisinde generic türden bir bağlı liste _(Linked List)_ kullanılmakta. Önce bu veri yapısını inşa etmeyi öğrenmek gerekiyor. Bu kodda generic verisyona gitmeden bir sürecin sıralı loglarının bağlı liste olarak tutulduğu basit kurgu söz konusu. Her log bilgisi Node isimli bir struct ile temsil ediliyor. ProcessLog isimli veri yapısı Node örneklerini ardışıl olarak tutan bir bağlı liste veri yapısını temsil ediyor.\n\n```bash\ncargo new linked_list --lib\ncd linked_list\ncargo test\n```\n\n![./assets/screenshot_14.png](./assets/screenshot_14.png)\n\n### Özel Yineleyiciler _(iterator)_ Oluşturmak\n\nÖrnekte basit bir liste veri yapısının elemanlarında ileri yönlü hareket etmek için iterator deseninden nasıl yararlanıldığı ele alınmaktadır. Bu amaçal Iterator ve IntoIterator isimli standart kütüphanedeki trait'lerin generic List veri yapısı için uyarlanması söz konusudur. Bu uyarlama rust derleyicisi için anlamlıdır ki kendi veri türümüz üstünden next fonksiyonu çağırıldığında veya bir for döngüsü ile kullanıldığında nasıl hareket edeceğinin öğretilmesi gerekir\n\n```bash\ncargo new custom_iterator --lib\ncd custom_iterator\ncd src\n# örnekte kullanılan generic liste veri yapısını ayrı bir modüle yerleştirmek için klasör açılır\nmkdir list\ncd list\ntouch mod.rs\ncd ..\ncd ..\ncargo test\n```\n\n![./assets/screenshot_13.png](./assets/screenshot_13.png)\n\n### Yararlı Iterator Kullanımları\n\nArdışıl eleman yapılarında iter metotu arkasından ulaşılabilen kullanışlı pek çok fonksiyon bulunmakta. next, map, fold, collect, zip, find, position, take vs Bu fonksiyonlar sadece nesne kümelerinde hareket etmek değil dönüştürme _(transformation)_, filtreleme, toplu hesaplama _(aggregation)_ gibi işlemler için de önemli. Örnekte bu fonksiyon kullanımlarına yer veriliyor.\n\n```bash\ncargo new iterations --lib\ncd iterations\ncargo test\n```\n\n![./assets/screenshot_15.png](./assets/screenshot_15.png)\n\n### Unsafe Kodlama\n\nRust'ın C diline yakınlaştığı yerlerden birisi de unsafe halidir. Unsafe modda iken derleyicinin uygulamayı kontrol eden güven mekanizması kapatılır. Unsafe sayılan fonksiyonların çağırılmasında, mutable işaretlenmiş statik değerlere erişmekte veya değiştirmekte, pointer referanslarının kaldırılmasında vs kullanılabilir.\n\n```bash\ncargo new easy_unsafe --lib\ncd easy_unsafe\ncargo test\n```\n\n![./assets/screenshot_16.png](./assets/screenshot_16.png)\n\n### Paylaşımlı Sahiplik _(Shared Ownership)_\n\nRust dilinde bir garbage collector mekanizması yoktur. Bunun yerine sahiplenme _(ownership)_ ve ödünç alma _(borrowing)_ kavramları öne çıkar ve oldukça önemlidirler. Mevzu bir değişkenin yaşamı ile ilgilidir. Normal şartlarda scope'lar değişkenleri sahiplenirler ve scope dışına çıkılınca değişken artık kullanılamaz. Tabii sahiplikler iç scope'lara transfer edilebilir ve tekrar geri gelebilir. Geçici transferlerde ödünç alma kullanılır ancak bazı hallerde yönetimleri karmaşıktır. Kitabın bu kısmında paylaşılmış sahiplik ile ilgili örnek kodlar yer alıyor ve smart pointer kullanımının performans açısından önemi vurgulanıyor.\n\n```bash\ncargo new shared_ownership --lib\ncd shared_ownership\n\n# Örnekte benchmark testi yapıldığından rust'ın nightly build sürümü gerekiyor.\nrustup default nightly\n\n# test için\ncargo test\n\n# benchmark sonuçlarını görmek için\ncargo bench\n```\n\n![./assets/screenshot_17.png](./assets/screenshot_17.png)\n\n![./assets/screenshot_18.png](./assets/screenshot_18.png)\n\n### Değiştirilebilir Paylaşımlı Sahiplik _(Mutable)_\n\nSalt okunabilir verileri sahipliği paylaşarak yönetmek adına bir önceki bölümdeki gibi Rc _(Reference Counting)_ kullanımı yeterlidir. Ancak değeri değiştirilebilir verilerde Refcell, Cell, Cow _(Clone on Write) gibi enstrümanlar ile veriyi referans olarak paylaşmak tercih edilir. Örnekte bu tiplerin nasıl kullanıldığı ve veri değiştirme operasyonlarındaki performans metrikleri ele alınmakta.\n\n```bash\ncargo new shared_mutable_ownership --lib\ncd shared_mutable_ownership\n\n# Örnekte benchmark testi yapıldığından rust'ın nightly build sürümü gerekiyor.\nrustup default nightly\n\n# test için\ncargo test\n\n# benchmark sonuçlarını görmek için\ncargo bench\n```\n\n![./assets/screenshot_20.png](./assets/screenshot_20.png)\n\nTest sonuçlar enteresan değil mi? Standart yöntem en performanslısı gibi görünüyor.\n\nNormal test sonuçları, \n\n![./assets/screenshot_19.png](./assets/screenshot_19.png)\n\nve borrow sonrası borrow_mut kullanılması sırasında oluşan ihlal sonucu panic durumu.\n\n![./assets/screenshot_21.png](./assets/screenshot_21.png)\n\n### Referanslar için Yaşam Ömrü Doğrulaması _(Lifetimes Validations)_\n\nKitabın izleyen bölümünde referansların lifetime belirteçleri ile kullanımına yer veriliyor lakin lifetime mevzusunu biraz unutmuş gibiyim. Öncesinde ne olduğunu hatırlamak üzere izleyen örneğe başvuruyorum. Her referansın scope bazında bir yaşam ömrü _(lifetime)_ vardır. Bunu belli haller dışında açıkça belirtmemize gerek yoktur ancak içiçe scope kullanımları, referansların fonksiyonlara taşınması gibi hallerde Rust'ın ödünç alma kontrol mekanizması _(borrow cheker)_ çalışır ve doğru görünen kod derlenmez. Bu durumda programcının açıkça _(explicit)_ lifetime kapsamını belirlemesi yani referansa dipnot _(annotation)_ eklemesi gerekir.\n\n```bash\ncargo new lifetimes --lib\ncd lifetimes --lib\ncargo test\n```\n\nborrow cheker mekanizmasının #1 senaryosunda tespit ettiği ihlal durumu\n\n![./assets/screenshot_22.png](./assets/screenshot_22.png)\n\nfonksiyona lifetime belirtmeden referans geçtiğimiz #3 nolu senaryodaki ihlal durumu.\n\n![./assets/screenshot_23.png](./assets/screenshot_23.png)\n\nfonksiyon dönüş referansı ile parametrelerin yaşam ömürlerinin uyuşmamasını ele alan #5 senaryosundaki durum.\n\n![./assets/screenshot_24.png](./assets/screenshot_24.png)\n\n### Referanslar için Yaşam Ömrü Doğrulaması Bölüm 2\n\nBir önceki örnekle referans türlerinin yaşam sürelerini yönetmeyi hatırladıktan sonra tekrar kitabın ilgili bölümündeki örneğe döndüm. Referans kullanmanın bir sebebi de bellekte sürekli yer ayırıp kopyalama işlemleri nedeniyle oluşacak performans kayıplarının önüne geçmektir. Bununla ilgili kitap düşündürücü bir soru soruyor. Referans edilen orjinal değer scope dışına çıktığında, referansa ne olur? İşte bu noktada lifetimes belirteçleri ile derleyiciye yol göstermek gerekiyor. Örnekte temel bir istatistik hesaplaması için kullanılan Struct veri yapısında lifetimes bilgisinin nasıl kullanıldığı gösterilmekte.\n\n```bash\ncargo new lifetimes_2 --lib\ncd lifetimes_2\ncargo test\n```\n\n![./assets/screenshot_25.png](./assets/screenshot_25.png)\n\n### Trait Bounds\n\nRust derleyicisine belli bir tipin sahip olduğu ve başka tiplerle ortaklaşa paylaşabileceği davranışları söylemek için bunu soyutlaştırmamızı sağlayan trait enstrümanından yararlanıldığını biliyoruz. Birde trait bounds meselesi var. Örnek bununla ilgili.\n\n```bash\ncargo new trait_bounds --lib\ncd trait_bounds\ncargo test\n```\n\n#3 numaralı pratikte Debug Trait bildirimi yapılmadığında derleyicinin verdiği hata aşağıdaki gibidir.\n\n![./assets/screenshot_26.png](./assets/screenshot_26.png)\n\nSon çıktı.\n\n![./assets/screenshot_27.png](./assets/screenshot_27.png)\n\n### Generic Veri Türleri\n\nKitabın bu reçetesinde generic bir veri yapısı nasıl yapılır konusu ele alınmakta. Örnekte ilk olarak bir kompleks sayı veri tipini generic olarak tasarlayıp kullanmaktayız. Ardından generic bir liste türü tasarlıyoruz. Generic liste için data isimli bir modül kullanmaktayız.\n\n```bash\ncargo new generics --lib\ncd generics\ncd src\nmkdir data\ncd data\ntouch mod.rs\ncd ..\ncd ..\ncargo test\n```\n\n![./assets/screenshot_28.png](./assets/screenshot_28.png)\n\n## day03 - Paket Yönetimi ve Cargo ile Çalışmak\n\nKitabın üçüncü bölümüne ait çalışmalar. Bu bölümde cargo aracı ile proje yönetimine ait reçetelere yer verilmekte.\n\n### Workspace ile Çalışmak\n\ncargo aracı her şeyi klasör yapısına göre ele alınır. Klasik bir .net projesindeki Solution için Rust tarafında klasör mantığına göre tasarlanan workspace' ler kullanılır. Özellikle çok sayıda crate içeren projelerde workspace oluşturarak ilerlenir.\n\n```bash\n# day03 klasöründen işlemlere devam edilir\n\n# Bir Workspace oluşturulur\nmkdir -p rogue-one\ncd rogue-one\n\n# main fonksiyonunu içeren ana proje oluşturulur\ncargo new program\n\n# program tarafından kullanılacak bir crate kütüphanesi oluşturulur\ncargo new utility --lib\n\n# yine örnek bir kütüphane daha eklenir\ncargo new business --lib\n\n# cargo komutunu workspace içindeki diğer projeler için tek noktadan kullanabilmek istiyorsak\n# workspace root klasöründe bir cargo.toml dosyası açıp içeriğini ilgili projelerle donatmalıyız\n# örnek için rogue-one klasöründe.\ntouch cargo.toml\n\n# sonrasında rogue-one klasöründe run, test ve build gibi komutları kullanabiliriz\n\n# main fonksiyonunun olduğu program çalışır\ncargo run\n\n# workspace projesinde ne kadar test varsa koşulur\ncargo test\n# dilersek workspace içerisindeki sadece belli bir projenin testlerini işlettirebiliriz.\ncargo test -p business\n\n# build işlemi için\ncargo build\n```\n\n![./assets/screenshot_29.png](./assets/screenshot_29.png)\n\n_cargo build_ işlemi sonrası çalıştırlabilir binary dosyaları target klasörü altında konuşlanacaktır.\n\n![./assets/screenshot_30.png](./assets/screenshot_30.png)\n\n### crates.io ile Çalışmak\n\nDilersek kendi kod sandıklarımızı _(crate)_ herkesin erişimine açabiliriz. Bunun için ilgili paketleri uygun şekilde crates.io sitesine yüklemek yeterlidir. İlk olarak [crates.io](crates.io) sayfasına gidilir ve var olan github hesabı ile login olunur. Sonrasında __Account Settings__ kısmına gelinir ve API erişimi sağlanabilmesi için yeni bir token istenir. Sonuç itibariyle sistemimizde cargo aracını kullanarak crates.io ile çalışmak için bir şekilde kendimizi doğrulatmalıyız. Bu işlemi terminalden aşağıdaki komutu vererek yapabiliriz.\n\n```bash\ncargo login [buraya sizin için üretilen token eklenecek]\n\n# sonrasında yeni bir crate oluşturarak ilerleyebiliriz\ncargo new event-queue --lib\ncd event-queue\ncargo test\n\n# crates.io' da görünmesi amacıyla bir Readme.md dosyası da eklenir.\n# sonrasında paketin oluşturulması için aşağıdaki komut kullanılır.\n# Bu işlem öncesinde commit edilmemiş kod kalmamalı ve ayrıca cargo.toml dosyasında paket için gerekli tüm bilgiler yer almalıdır.\ncargo package\n\n# Ardında paket crates.io ortamına yollanır.\ncargo publish\n```\n\nUygulamanın test sonuçları;\n\n![./assets/screenshot_31.png](./assets/screenshot_31.png)\n\nEksik commit varsa;\n\n![./assets/screenshot_32.png](./assets/screenshot_32.png)\n\nPackage oluşturma ve publish işlemleri başarılı oluşursa;\n\n![./assets/screenshot_33.png](./assets/screenshot_33.png)\n\n### Dış Kütüphanelerin Kullanımı\n\nPek çok programlama platformunda olduğu gibi Rust için bir paket yönetim sistemi mevcut. Cargo bunu sağlamakta. Önceki örnekte bir crate tasarlayıp crates.io sitesine yüklemiştik. Bu tip bağımlılıkları _(dependencies)_ projelerimizde kullanmak için cargo.toml dosyasında gerekli düzenlemleri yapmak gerekiyor. Kullanılacak kütüphaneleri crates.io'dan veya github gibi kaynaklardan alabiliriz. Kitabın ilgili bölümünde buna ait bir örnek geliştirilmekte.\n\n```bash\ncargo new external-libraries --lib\ncd external-libraries\n\n# toml dosyasına [[bench]] kısmı eklendikten sonra\nmkdir benches\ncd benches\ntouch fibonacci_performance.rs\n\ncd ..\ncargo test\n\n# benchmark testleri için\ncargo bench\n```\n\nTest sonuçları;\n\n![./assets/screenshot_34.png](./assets/screenshot_34.png)\n\nBenchmark sonuçları;\n\n![./assets/screenshot_35.png](./assets/screenshot_35.png)\n\n### Test İpuçları\n\nŞu ana kadarki kodlarda ağırlıklı olarak test yazıldı. Sıradaki reçetede testlerle ilgili farklı özelliklere de yer verilmiş.\n\n```bash\ncargo new more-test --lib\ncd more-test\n\n# testleri koşturmak için normalde aşağıdaki komut veriliyor\ncargo test\n\n# sadece belli bir testin koşulmasını aşağıdaki komutla sağlayabiliriz\ncargo test tests::sum_of_two_works_test\n\n# test fonksiyonlarından terminale bilgi verilen print çağrılarını da görmek için aşağıdaki komutu kullanabiliriz\ncargo test -- --nocapture\n\n# çalıştırmak istediğimiz testleri içinde geçen kelimelere göre filtreleyerek koşturabiliriz\ncargo test seconds\n\n# Paralel koşan testlerin thread sayılarını kontrol edebiliriz. \n# Örneğin hepsinin tek bir thread içinde koşmasını istersek aşağıdaki terminal komutunu kullanabiliriz.\n# 1 yerine kaç thread açılmasını istersek yazabiliriz.\ncargo test -- --test-threads 1\n```\n\n_cargo test_ çalışmasında ilk dikkat çekici nokta testlerin eş zamanlı olarak başlatılması ve paralel koşmalarıdır. Bu nedenle toplam çalışma süresi en çok beklenen thread süresi kadar sürmüştür. Ayrıca _[ignore]_ ile işaretlenen test atlanmıştır.\n\n![./assets/screenshot_36.png](./assets/screenshot_36.png)\n\nSadece belli bir testin koşulması;\n\n![./assets/screenshot_37.png](./assets/screenshot_37.png)\n\nnocapture ile println! makro çıktılarının görülmesi;\n\n![./assets/screenshot_38.png](./assets/screenshot_38.png)\n\nİçinde seconds kelimesi geçen testlerin koşturulması;\n\n![./assets/screenshot_39.png](./assets/screenshot_39.png)\n\nTestlerin tamamının tek bir thread içinde koşturulması;\n\n![./assets/screenshot_40.png](./assets/screenshot_40.png)\n\n## day04 - Concurrency\n\nRust dilinin güçlü olduğu yerlerden birisi de eş zamanlılık ve paralel çalıştırma işleridir. Sahiplenme _(Ownership)_ ve ödünç alma _(borrowing)_ yetenekleri özellikle veritabanı dünyasında sıklıkla karşılaşılan veri odaklı anormalliklerin _(data races)_ benzerlerinin program tarafında yaşanmasını önler. Bunun en büyük sebeplerinden birisi aksi belirtilmedikçe değişkenlerin değiştirilemez _(immutable)_ olması ve değiştirilebilir _(mutable)_ değişkenler söz konusu olduğunda da bu değişken verisine sadece bir tek referans verilmesinin sağlanmasıdır. Bu tip kısıtlar Rust tarafındaki Concurrency yetkinliklerinin diğer dillere göre nispeten daha kolay ele alınmasını sağlamakta. Kitabın bu bölümünde Concurrency ile ilgili çeşitli örneklere yer verilmekte.\n\nİlave bilgiler;\n\n- Race Conditions: thread'lerin veri veya kaynaklara tutarsız sırada erişmesi.\n- Deadlocks; iki thread'in birbirini beklemesi ve işlerini bitirmek için birbirlerinin sahip olduğu kaynaklar üzerinde işlem yapmaya çalışması.\n- Rust standart kütüphanesi 1:1 thread modelini destekler. Bir sistem programlama dili olduğundan green-threading model olarak da anılan M:N için çeşitli crate desteği vardır.\n\n### Temel Operasyonlar\n\nKitabın sonraki bölümünde önce thread kullanımı için temel bir örnek yapmak iyi olabilir.\n\n```bash\ncargo new thread-fundamentals\ncd thread-fundamentals\ncargo run\n```\n\nİlk çalışmada dikkat edilmesi gereken nokta içerideki thread daha işini bitirmeden ana thread'in _(main fonksiyonu)_ sonlanmasıdır.\n\n![./assets/screenshot_44.png](./assets/screenshot_44.png)\n\nİkinci çalışmada _(case2 fonksiyonu)_ ana thread'in diğer thread'in işleyişini bitirmesi join çağrısı ile sağlanır. Bir süre iki thread'den değerler alınır sonra kalan thread'in işleyişinin tamamlanması beklenir.\n\n![./assets/screenshot_45.png](./assets/screenshot_45.png)\n\njoin fonksiyonu ile bekletmenin yapıldığı yer de önemlidir. Örneğin 14ncü satırdaki join çağrısını ana thread'in işleteceği for döngüsü önüne(8nci satır) alırsak farklı bir sonuç elde ederiz. Önce t1'in bitmesi beklenir sonrasında ana thread'in işleri yapılmaya başlanır.\n\n![./assets/screenshot_46.png](./assets/screenshot_46.png)\n\n### Veriyi Yeni Thread'lere Taşımak\n\nİlk örnekte spawn fonksiyonu ile oluşturulan thread'lerde veri paylaşımı konusu ele alınmakta.\n\n```bash\ncargo new simple-threads\ncd simple-threads\ncargo run\n```\n\nBaşlangıçta ana thread içinden başlatılan başka bir thread'in işini bitirmesi bekleniyor.\n\n![./assets/screenshot_41.png](./assets/screenshot_41.png)\n\nİkinci senaryoda içinde thread başlatan bir fonksiyona main içinden tanımlı değişkenler gönderiyoruz. Bu değişkenleri diğer thread'te kullanmak istediğimizde ise borrow checker mekanizması devreye giriyor ve aşağıdaki hatayı alıyoruz.\n\n![./assets/screenshot_42.png](./assets/screenshot_42.png)\n\nHatanın çözümünde spawn fonksiyonunda move kullanılması yeterli. move ile thread için söz konusu olan varsayılan ödünç alma davranışını değiştirip ana scope'tan thread'in açıldığı scope'a taşınabilmesine izin veriyoruz. Taşınabilecek değişkenlerin Copy trait'ini uygulamış olmaları önemli.\n\n![./assets/screenshot_43.png](./assets/screenshot_43.png)\n\n### Çoklu İş Parçacıkları _(Threads)_ Oluşturmak\n\nBüyük ölçekli veri kaynakları üzerinden paralel olarak işlemler çalıştırmak önemlidir. Bu amaçla sıkılıkla kullanılan yöntemlerden birisi de map/reduce tekniğidir. İzleyen kod parçasında birden fazla iş parçacığının birlikte ele alınması konusu incelenmekte.\n\n```bash\ncargo new multiple-threads\ncd multiple-threads\n\ncargo run\n```\n\nToplam işlem süresi ve oluşan thread numaralarının ele alındığı çalışma çıktısı.\n\n![./assets/screenshot_47.png](./assets/screenshot_47.png)\n\n### İş Parçacıkları Arası Haberleşme için Kanal _(Channel)_ Kullanımı\n\nKitabın bu reçetesinde thread'ler arasında deadlock gibi sorunlara sebebiyet vermeden mesaj alışverişinde bulunabilmek için kanallardan nasıl yararlanıldığı örneklenmte. İlk örnekte üç adet mesaj yayıcı söz konusu.\n\n```bash\ncargo new thread-channels\ncd thread-channels\n\ncargo run\n```\n\n![./assets/screenshot_48.png](./assets/screenshot_48.png)\n\n### İş Parçacıklarında Ortak Nesne Kullanımı\n\nPek çok çözümde n sayıda iş parçacığının aynı veri kümesi üzerinde çalışması ve doğal olarak verinin durumunun _(state)_ sürekli değişimi söz konusudur. Lakin bazı durumlarda bu thread işleyişinin sıralı şekilde kontrol altına alınması gerekebilir. Bu gibi durumlarda ağırlıklı olarak Mutex _(MUTual EXclusion)_ veya Semaphore gibi yapılar kulanılmakta. Kitabın sıradaki reçetesinde Mutex ile ilgili bir konu incelenmekte. Örnekte aynı vektör içeriğine sıralı olarak veri yazan n sayıda thread'in işleyişi ele alınmaktadır.\n\n```bash\ncargo new sharing-mutable-states\ncd sharing-mutable-states\ncargo run\n```\n\nÖrnekte çalışan 4 iş parçacığı aynı vektöre Odd ve Even değerlerini sırayla ekler. Her bir iş parçacığı vektördeki son değişimleri bilir. Vektör eleman sayısı 10'a geldiğinde iş parçacığında yer alan sonsuz döngüden ve iş parçacığından çıkılır. Her bir iş parçacığı için geriye kalan bir ekleme işlemi daha söz konusudur. Bu nedenle vektör 14 elemanlı olarak oluşur.\n\n![./assets/screenshot_49.png](./assets/screenshot_49.png)\n\n### Process Başlatma ve Çoklu Process Kullanımı\n\nİşletim sistemlerinde uygulamalar process'ler içerisinde çalışır. Rust ile de harici process'leri kod içerisinde başlatmak mümkündür ki bunlar alt process'ler de olabilir. Kitabın bu bölümünde başlatılan bir process'in girdilerinden elde edilen çıktıların başka bir process'e girdi olarak verilmesi de örneklenemkte. Ama öncesinde temel process çağırımlarına bakmak lazım. İlk denemede kobay ve hiçbir işe yaramayan ama terminalden komut alarak çıktı üreten bir programın, bir rust kodu içerisinden çalıştırılması söz konusu. Reçetede dikkatimi çeken bir ifade de günümüz orkestra aktörlerinden Kubernetes, Docker Swarm, Mesos'a bir cümle ile atıfta bulunulmuş olması. Bu tip container sistemleri sebebiyle child process'lerin yönetiminin de önemli hale geldiğine değiniliyor.\n\n```bash\n# Sembolik olarak komut satırından parametre olarak gelen şehrin hava durumu bilgisini verecek bir binary'miz olsun.\ncargo new weather\ncd weather\ncargo run\n\n# Bu da weather uygulamasını process olarak çağırıp sonucunu alacak olan program\ncargo new simple-process\ncd simple-process\ncargo run\n\n# Kendi içinde processleri haberleştiren diğer örnek\ncargo new multi-process\ncd multi-process\ncargo run\n```\n\nWeather isimli exe'nin terminalden örnek çalıştırılması.\n\n![./assets/screenshot_50.png](./assets/screenshot_50.png)\n\nWeather isimli uygulamayı kendi içinden çağırıp çıktısını alan diğer uygulamanın örnek çalışması.\n\n![./assets/screenshot_51.png](./assets/screenshot_51.png)\n\ncat ile pipeline'a bilgi yazıp onu okuyan alt processler örneğini bir bash terminalde denemek gerekiyor. _(Linux olduğu için)_\n\n![./assets/screenshot_52.png](./assets/screenshot_52.png)\n\n### Paralel Çalıştırma\n\nBu reçetede sıralı yürütülen işleri paralel çalışacak hale getirmek üzerinde durulmuş ve Rayon [Rayon-Rs](https://github.com/rayon-rs/rayon) isimli bir crate'in kullanımı örneklenmiş. Ayrıca sonuçları karşılaştırmak için benchmark testleri yapılmış. Örnekte bir sayı dizisindeki sayıların karelerinin toplamı ele alınıyor. Ancak iterasyon hem normal hem de rayon paketi sayesinde paralel işletilmekte. Küçük veri kümesi üzerinde çok fark yok ancak tersi durumda süre farkı oluşuyor.\n\n```bash\ncargo new parallelism --lib\ncd parallelism\ncargo test\n\n# benchmark ölçümleri içinse\nmkdir benches\ncd benches\ntouch benchmarks.rs\ncd ..\ncargo bench\n```\n\nTest çıktıları;\n\n![./assets/screenshot_53.png](./assets/screenshot_53.png)\n\nBenchmark sonuçlar _(100.000.000 luk rastgele int kümesi için)_\n\n![./assets/screenshot_54.png](./assets/screenshot_54.png)\n\n### Kısa Bir Mola _(Ownership Mevzusunu Hatırlamak)_\n\nArada bir Rust'ın temel bilgilerini hatırlamakta yarar var. Ownership konusu bunlardan birisi. İyi hatırlamak lazım. İzleyen örnek bu amaçla yazıldı.\n\n```bash\ncargo new remember-ownership\ncd remember-ownership\ncargo run\n```\n\nİlk durum. Drop konusu.\n\n![./assets/screenshot_55.png](./assets/screenshot_55.png)\n\nİkinci durum. Move.\n\n![./assets/screenshot_56.png](./assets/screenshot_56.png)\n\nÜçüncü durum. Fonksiyon parametrelerinde move durumu.\n\n![./assets/screenshot_57.png](./assets/screenshot_57.png)\n\nBeşinci durum. Kendi struct türümüzde Copy, Clone trait'lerini uygulamadığımızda move operasyonlarının sonucu. _(Beklendiği üzere)_\n\n![./assets/screenshot_58.png](./assets/screenshot_58.png)\n\nDokuzuncu durum. String literal'de lifetime durumuna dikkat etmezsek.\n\n![./assets/screenshot_59.png](./assets/screenshot_59.png)\n\nOnuncu durum. Bir struct içinde string literal kullanıp lifetime belirtmediğimiz durumda.\n\n![./assets/screenshot_60.png](./assets/screenshot_60.png)\n\nOnbirinci durum. Mutable bir değişkeni okuyan immutable bir değişken kullanıldığı durum.\n\n![./assets/screenshot_61.png](./assets/screenshot_61.png)\n\nYine 11nci duruma örnek bir hata çıktısı. _(iter_)\n\n![./assets/screenshot_62.png](./assets/screenshot_62.png)\n\nVe bir kez daha 11nci duruma ait örnek hata çıktısı. _(iter _ mut kullansak da)_\n\n![./assets/screenshot_63.png](./assets/screenshot_63.png)\n\nBu ara tekrardan şu sonuçlara varabiliriz.\n\n- Bir değer ataması _(value assignment)_ yaptığımızda onu bir değişkene _(variable)_ bağlarız. Değerin tek sahibi _(owner)_ bu değişken olur.\n- Bir değerin sahibi kapsam _(scope)_ dışına çıkınca bellekten düşürülür _(drop)_\n- Bir değeri yeniden atadığımızda _(reasignment)_ taşınması _(move)_ veya sahipliğinin _(ownership)_ el değiştirmesi söz konusu olur.\n- Bir değer taşıması söz konusu olduğunda eski atanan bir daha asla kullanılamaz.\n- Ödünç _(borrow)_ alınan bir referans, temel değerden daha uzun süre yaşayamaz.\n- Bir referansın sahibi kimse, değişken önüne _\u0026_ operatörü konulup yeniden atama yoluyla ödünç alınıp _(borrowing)_ kullanılabilir.\n- lifetime parametreleri _(sıklıkla 'a şeklinde yazılır)_ ödünç alınan bir referansın kapsamını temsil eder.\n- Rust derleyicisi birden fazla değişken okurunun veya tek bir değişken yazarının faal olarak kullanılmasına izin verir ve ikisinin de aynı anda etkinleşmesine müsaade etmez. Ancak senkron geçişlerle kullanım sağlanabilir.\n\n### Paylaşımlı Değişmez Haller _(Shared Immutable States)_\n\nKısa bir hatırlatma arasından sonra tekrar kitaba dönebilirim. Sıradaki örnek bir kanal oluşturulup farklı thread'ler içerisinde klonları oluşturulan sender ve receiver değişkenlerinin aynı fonksiyona parametre olarak yollanması halinde oluşan _\"...cannot be shared between threads safely\"_ durumunu anlatmakta.\n\n```bash\ncargo new shared-immutable-states\ncd shared-immutable-states\ncargo test\n```\n\n![./assets/screenshot_64.png](./assets/screenshot_64.png)\n\n### Asenkron Mesajlaşmada Actor Kullanımı\n\nBüyük yazılım sistemlerini mikroservis gibi yapılara döndürdüğümüzde oluşan onlarca servis için mesajlaşmalar önem kazanıyor. Bunun gibi çeşitli process veya fonksiyonların mesajlaşması denince akla gelen enstrüman Actor Model _(Akka)_ Esasında bu modelin ilk kullanıldığı yer Erlang dili. Günümüzde Javascript'in Web Worker'ları akka'nın temel ilkeleri üzerine inşa edilmiş. Hatta akka için yazılımış ayrı çatılar da mevcut _(Akka.net gibi)_ Actor olarak nitelendirilen şey esasında bir bilgisayar prosesi. Ayrıca ona nasıl mesaj yollanacağına dair bir adres de bulunuyor. Bu adresi mail adresine de benzetebiliriz sanıyorum ki. Bir aktörün birden fazla adresi de olabilir. Hatta bir adrese birden fazla aktörü de bağlayabiliriz. Düşününce yoğun trafik alan bir uygulamanın ölçeklenmesinde aktör sayısının yetersiz kaldığı durumda bu taktik epeyce işe yarar. Aslında aktörlerin görevi bellidir. Veri saklamak, diğer aktörlerden mesaj almak, diğer aktörlere mesaj göndermek ve son olarak alt aktör _(child actor)_ nesneleri oluşturmak. Bir aktörün sahip olduğu veri _(ki nesnenin state'idir aynı zamanda)_ başka bir aktör tarafından doğrudan değiştirilemez. Değişiklik için aktöre mesaj gönderilmesi ve bunun sorulması gerekir. Aktörler arasındaki mesajlaşma ilke olarak asenkron gerçekleşir ve dolayısıyla mesajların senkron halde gitmesinin bir garantisi yoktur ki bu durum senkronluğun önemli olduğu senaryolarda akka'nın ideal olmayacağını gösterir. Aktörler t anında yanlızca bir mesajı işlemek üzere tasarlanmıştır. Diğer yandan çocuk aktörler oluşturup kendilerin gelen bir mesajı işlenmek üzere alt aktörlere dağıtabilirler. Bu ilkeler açısından bakıldığında bir programın asenkron işleyen parçalarının haberleşmesinde aktör modelinden yararlanılabileceğini söyleyebiliriz. Rust tarafında da asenkron mesajlaşmalar için actor model kullanılabiliyor. Kitabın bu kısmında _actix_ paketinden nasıl yararlanılacağı örnek senaryo üzerinden anlatılmış.\n\n```bash\n# ilk olarak temek bir actix örneği yapalım.\ncargo new hello-actix\ncd hello-actix\ncargo run\n\n# İkinci bir uygulama örneği.\ncargo new async-with-actix\ncd async-with-actix\ncargo run\n\n# Aktörlerin paralel çalışmasının ele alındığı örnek için\ncargo new actix-syncarbiter\ncd actix-syncarbiter\ncargo run\n```\n\nİlk örnekte actix'in hello world'ü yer alıyor.\n\n![./assets/screenshot_65.png](./assets/screenshot_65.png)\n\nİkinci örneğin çalışma zamanı görüntüsü.\n\n![./assets/screenshot_66.png](./assets/screenshot_66.png)\n\nSyncArbiter ile reçetenin belirttiği örneğin çıktısı. _actix kütüphanesinden bazı değişiklikler nedeniyle kitaptaki örnek çalışmadı. Biraz değişiklik yapmak gerekti._\n\n![./assets/screenshot_67.png](./assets/screenshot_67.png)\n\n## day05 - Hata Yönetimi\n\nKitabın _Handling Errors and Other Results_ bölümüne ait çalışmalar.\n\nRust dilinde hatalar olağan akışın bir parçası olarak görülür ve iki ana kategoride değerlendirilirler: düzeltilebilecek olanlar _(recoverable) ve kurtarılamayacaklar _(unrecoverable)_. Söz gelimi açılmak istenen bir dosyanın bulunamaması düzeltilmesi mümkün bir hata türüdür. Sorun kullanıcıya bildirilebilir ve yeniden denetilebilir. Fakat bir dizinin olmayan indisindeki elemana erişmeye çalışmak kurtarılabilir türden değildir. Dikkat edileceği üzere bazı dillerde bu tip bir ayrıma pek rastlanmaz ve tümü exception handling gibi mekanizmalarca ele alınır. Rust dilinde exception mekanizması bulunmaz. Bunun yerine Result\u003cT,E\u003e, Option gibi türlerle her şeyin bir dönüşünün olması istenir. Kurtarılabilir hata senaryolarında Result\u003cT,Err\u003e tipinin kullanımı son derece yaygındır lakin kurtarılamayan hata senaryoları için panic durumu devreye girer. Bir panik hali panic! makrosunun doğrudan çağırılmasyıla bilinçli olarak da oluşturulabilir. Panik oluşması halinde sistemin çalışması anında kesilir ve geriye doğru gidilerek bellek üzerinde ayrılan tüm kaynakların temizlenmesi süreci başlatılır. Bu, stack üstüne alınan ne kadar veri ve onunla ilgili fonksiyon varsa tek tek ilgilenilmesi anlamına da gelir. Maliyet açısından düşük kaynak tüketemi olan programlarda bu temizleme operasyonunu hemen atlayıp işletim sistemine bırakmak da mümkündür. Bunun için toml dosyasına aşağıdaki gibi bir ek yapmak yeterli olur.\n\n```rust\n[profile.release]\npanic = 'abort'\n```\n\n### Panic Sorumluluğunu Almak\n\nCevap vermeyen sunucu, işletim sistemi problemleri, geçersiz konfigurasyon dosyaları vb durumlarda çalışmakta olan thread'in devam etmesinin bir yolu kalmayabilir. Bu durumlar Rust tarafında kurtarılamayan _(unrecoverable)_ hatalar olup panic olarak değerlendirilir. Bu reçetede _panic!_ makrosunun temel kullanımlarına yer verilmiş.\n\n```bash\n# Buradan itibaren örnekler day05 klasörü altında icra edilemkteler\n\ncargo new hello-panic --lib\ncd hello-panic\ncargo test\n```\n\nBilinçli panic! makro çağrısı sonrası kodların işletilmediğinin gösterildiği duruma ait ekran görüntüsü.\n\n![./assets/screenshot_68.png](./assets/screenshot_68.png)\n\nPanik senaryolarında çalışma zamanında geçilen yerleri görmek ve için RUST_BACKTRACE isimli çevre değişkenin 1 değeri verilerek ilerlenebilir _(Bir nevi stack trace olarak düşünebiliriz sanırım)_ Windows tarafında powershell'de aşağıdaki komut ile bu işlem gerçekleştirilebilir.\n\n```powershell\n# Panik ile ilgili detay açmak için\n$env:RUST_BACKTRACE=1; cargo run\n\n# Tekrar eski konumuna döndürmek için\n$env:RUST_BACKTRACE=0;\n```\n\n### Birden Fazla Hatanın Ele Alınması\n\nSıradaki reçetede birden fazla hatanın ele alınması gerektiği durumlarda nasıl ilerleneceğine dair bir örneğe yer verilmiş. Örnekte kullanıcı tanımlı hata yapıları hazırlanıyor ve bunlara Error ile Display trait'leri uygulanıyor.\n\n```bash\ncargo new lot-of-error --lib\ncd lot-of-error\ncargo test\n```\n\n### Result Tipinin Verimli Kullanımı\n\nFonksiyonların dönüş türlerinde genellikle Option veya Result türlerinden yararlanılır. Özellikle olası hata durumlarının değerlendirilmesi gereken hallerde Result\u003cT,Err\u003e türü öne çıkar. Result veri yapısı aşağıdaki şekilde tanımlanmıştır. \n\n```rust\nenum Result\u003cT, E\u003e {\n   Ok(T),\n   Err(E),\n}\n```\n\nReçetede Result türünün verimli kullanımına ait örneklere yer verilmekte.\n\n```bash\ncargo new effective_result --lib\ncd effective_result\ncargo test\n```\n\n![./assets/screenshot_69.png](./assets/screenshot_69.png)\n\n### Diğer Hata Kontrol Pratikleri\n\nHata yönetimi ile ilgili diğer konuların toplandığı örnek. Result değerlerindeki hata bilgilerinde pattern matching kullanımı, ? operatörü ile kodun yalınlaştırılması, panic! makrosuna açıkça başvurulması, unwrap_or_else ile closure kullanımı, unwrap ve expect fonksiyonları gibi pratikler ele alınmıştır.\n\n```bash\ncargo new error-handling\ncd error-handling\ncargo run\n```\n\nÖrneğin çalışma zamanı çıktılarına ait ekran görüntüleri.\n\ncase 1'den,\n\n![./assets/screenshot_70.png](./assets/screenshot_70.png)\n\ncase 2'den\n\n![./assets/screenshot_71.png](./assets/screenshot_71.png)\n\ncase 4'ten\n\n![./assets/screenshot_72.png](./assets/screenshot_72.png)\n\n![./assets/screenshot_73.png](./assets/screenshot_73.png)\n\ncase 5'ten\n\n![./assets/screenshot_74.png](./assets/screenshot_74.png)\n\ncase 6'dan\n\n![./assets/screenshot_75.png](./assets/screenshot_75.png)\n\ncase 7'den\n\n![./assets/screenshot_76.png](./assets/screenshot_76.png)\n\n## day06 Makrolarla Çalışmak\n\nKod yazan kodlar veya metaprogramming'in Rust dilindeki karşılığı macro türüdür. Örneklerde sıklıkla kullandığımız makrolar vardı. println!, vec!, assert_eq!, concat!, stringify!, option_env!, cfg! vb. Bu makrolar aslında değişken sayıda parametre alabilen ve içerdikleri kod şablonlarına bu değerleri yerleştirerek bazı kodları otomatik olarak yazan yapılara sahip. Hatta makrolar sayesinde trait'lerin varsayılan versiyonlarının bir tipe otomatik olarak uygulanması da mümkündür. Örneğin Derive niteliğinde Copy, Clone gibi trait bildirimlerini yaptığımızda bir struct için bu davranışlara ait kodların otomatik olarak hazırlanması makronun işidir. Makroları sadece kod şablonları olarak düşünmemek gerekir. Asıl gücü üretilmek istenen kodun soyut sentaksına dair bir ağaç yapısı sunmasından gelmektedir. Makrolar derleme aşamasında işletilen kod parçalarıdır. Bu sayede programın ilerleyen safhalarında ihtiyaç duyulan kodların derleme aşamasında eklenmesi sağlanabilir. Yani derlenmiş kod parçalarını makrolar ile programa ekleyebiliriz. Parametre sayıları belirsiz olabileceğinden doğal olarak overload karaktersitiği gösterirler. Sentaks eşleştirme desenleri kullanırlar ama metinsel değiştirme değil de sentaks ağaç yapısını kullanırlar. Recursive davranış sergileyebilirler. Makroları kabaca _Rust kodu yazan Rust kodları_ olarak düşünebiliriz. vec! makrosunun rust kod içeriği örneğin aşağıdaki gibidir.\n\n```rust\n#[cfg(not(test))]\n#[macro_export]\n#[stable(feature = \"rust1\", since = \"1.0.0\")]\n#[allow_internal_unstable(box_syntax, liballoc_internals)]\nmacro_rules! vec {\n    () =\u003e (\n        $crate::__rust_force_expr!($crate::vec::Vec::new())\n    );\n    ($elem:expr; $n:expr) =\u003e (\n        $crate::__rust_force_expr!($crate::vec::from_elem($elem, $n))\n    );\n    ($($x:expr),+ $(,)?) =\u003e (\n        $crate::__rust_force_expr!(\u003c[_]\u003e::into_vec(box [$($x),+]))\n    );\n}\n```\n\nDikkat edileceği üzere parametre yapısının eşleştiği desene göre farklı bir dal çalışacaktır. Hiç eleman gönderilmediğinde boş bir vektörün oluşturulması söz konusu iken virgül notasyonu ile n sayıda elemean gönderildiğinde boxing kullanılaraktan da bir vecktör nesnesi oluşturulur. Bu noktada tüm dallarda rust_force_expr! isimli bir başka makroya başvurulduğunu da görmekteyiz. $ sembolü ile başlayan ifadeler aslında sentaks ağacındaki enstrümanları işaret eder. Kullanılabilecek olanları şöyle sıralayabiliriz.\n\n- _item_ ile fonksiyon, struct veya modül gibi bir enstrümanı ifade edebiliriz.\n- _block_ ile süslü parantezler içerisine alınmış kod ifadelerini işaret edebiliriz.\n- _stmt_ ile bir ifadeyi _(statement)_ belirtiriz.\n- _ty_ ile bir tip belirtilir.\n- _ident_ ile bir tanımlayıcı _(identifier)_ işaret edilir.\n- Bunlar gibi _pat, path, meta, expr, vis, tt_ gibi çeşitli token türleri vardır.\n\nKitabın bu bölümünde makrolarla ilgili pratiklere yer verilmekte.\n\n```bash\ncargo new hello-macros --lib\ncd hello-macros\ncargo test\n\ncargo new macros --lib\ncd macros\ncargo test\n```\n\nhello-macros uygulamasının çıktısı.\n\n![./assets/screenshot_77.png](./assets/screenshot_77.png)\n\nMakrolar _Declarative_ ve _Procedural_ olmak üzere iki kategoride değerlendirilirler. _Procedural_ formatta _Attribute-like, Functiona-like ve Derive_ olmak üzere üç alt kategoriye ayrılırlar. Declarative yaklaşımla geliştirilen makroların belli maliyetleri vardır. Binary'yi büyütürüler, derleme zamanını uzatırlar, değiştirme yetenekleri kısıtlıdır vs. Bu gibi sebeplerden procedural makrolar da tercih edilebilir. Procedural makrolar isteğe bağlı girdi alır ve işletilebilir rust kodu üretir. Ayrıca _token stream_ alıp başka bir _token stream_ döndürebilirler. Bir başka deyişle uygulandıkları türe yeni fonksiyonellikler katacak kod parçalarını parse edebilirler. Tüm struct türlerine otomatik json, xml, bson dönüştürme işlevsellikleri ekleyebildiğimizi düşünelim.\n\n```bash\ncargo new proc-macros --lib\ncd proc-macros\ncargo test\n```\n\nAttribute-like makro örneğinin bir çıktısı. Dikkat edileceği üzere makronun uygulandığı struct türünün içeriği ve makroya verilen parametreler compile aşamasında ekrana basılmıştır.\n\n![./assets/screenshot_78.png](./assets/screenshot_78.png)\n\nCase 5'e ait çalışma zamanı çıktısı. Derive macro kullanılan örnekteki Memory fonksiyonuna eklenen kod parçası ile davranışın sadece struct türlerine uygulanması garantilenmiştir.\n\n![./assets/screenshot_79.png](./assets/screenshot_79.png)\n\n## day07 - Diğer Dillerle Rust'ın Entegrasyonu\n\nKitabın bu bölümünde Rust ile diğer dil veya platformların nasıl entegre edileceğine dair örneklere yer verilmekte.\n\n### C İle Entegrasyon\n\nRust sonuç itibariyle sistem programlama konusunda öne çıkan ve C ile aynı domain üzerine oturan bir programlama dili. Ben örneği Windows tabanlı bir sistemde denediğim için C derleyicisi ve make programına ihtiyacım var ama WSL aktif ve bir Ubuntu sürümü yüklü olduğu için gerekli olan cc ve make araçlarına oradan ulaşılabilirim.\n\n![./assets/screenshot_80.png](./assets/screenshot_80.png)\n\nSenaryodaki Rust kütüphanesinde SHA256 ile encrypt işlemi yapan kobay bir fonksiyon bulunuyor. Bu fonksiyon, C ile yazılmış başka bir uygulama tarafından çağırılıyor. Benzer şekilde rust kütüphanesi içinden de C tarafında tanımlanmış iki fonksiyon çağırılmakta. Böylece C ve Rust çalışma zamanlar arasında nasıl fonksiyon çağrıları yapılabileceğinin bir yolunu öğrenmiş oluyoruz. \n\n```bash\n# Windows ortamında WSL ile Ubuntu üstünde de çalışılabilir.\n# C Compiler ve builder için versiyon kontrollerini aşağıdaki gibi yapabiliriz.\ncc --version\nmake --version\n\n# Örneğimiz day07 klasörü altında inşa ediliyor.\nmkdir integrate-with-c\ncd integrate-with-c\n\n# C kodları için bir klasör oluşturuyoruz.\nmkdir C\n\n# rust tarafı içinde bir library oluşturuyoruz.\ncargo new app --lib\n\n# rust kodları yazıldıktan sonra release işlemi icra edilir.\ncargo build --release\n```\n\nYukarıdaki build işlemi sonrası bulunulan platforma göre binary'ler üretilir. Linux tarafında libkrip.so, Windows tarafında ise libkrip.dll Bu dosyalar C programının bağlanacağı dinamik/statik kütüphanelerdir.\n\n![./assets/screenshot_81.png](./assets/screenshot_81.png)\n\n```bash\n# C program kodlarının yazılmasına başlanabilir.\ncd ..\ncd C\nmkdir src\ntouch src/main.c\ntouch Makefile\n\n# Derleme işlemler için Makefile içine yazılmış talimatlar işletilecektir.\nmake release\n\n# C kodu başarılı bir şekilde derlendikten sonra Linker için bir path bildirimi gerekebilir.\n# Nitekim aşağıdaki komuta göre libkript.so için path bilgisi boş gelmiştir.\nldd main\n\n# Dynamic Library yolu için LD_LIBRARY_PATH çevre değişkeni parametresini kullanarak bu sorun aşılabilir.\nLD_LIBRARY_PATH=../../app/target/release ./main\n```\n\n![./assets/screenshot_82.png](./assets/screenshot_82.png)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fburaksenyurt%2Fsilver-eureka","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fburaksenyurt%2Fsilver-eureka","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fburaksenyurt%2Fsilver-eureka/lists"}