Ana içeriğe geç

ch12-03-improving-error-handling-and-modularity

Modülerlük ve Hata Yönetimini İyileştirmek İçin Yeniden Yapılandırma

Programımızı geliştirmek için yapının ve olası hataları nasıl yönettiğiyle ilgili dört problemi çözeceğiz. Öncelikle, main fonksiyonumuz artık iki görev yerine getiriyor: argümanları yorumluyor ve dosyaları okuyor. Programımız büyüdükçe, main fonksiyonunun üstlendiği ayrı görev sayısı artacaktır. Bir fonksiyon sorumluluk kazandıkça, üzerinde düşünmesi zorlaşır, test edilmesi zorlaşır ve parçalarından birini bozmadan değiştirilmesi daha zor hale gelir. En iyisi, her bir fonksiyonun bir görevden sorumlu olduğu bir işlevselliği ayırmaktır.

not

Bu konu, ikinci bir problemle de bağlantılıdır:

query ve file_path programımız için yapılandırma değişkenleri olmasına rağmen, contents gibi değişkenler programın mantığını gerçekleştirmek için kullanılır. main giderek uzadıkça, kapsam içine almamız gereken değişken sayısı artar; kapsamda bulunan daha fazla değişken, her birinin amacını takip etmeyi zorlaştırır. En iyisi yapılandırma değişkenlerini tek bir yapı içinde toplamak ve amaçlarını belirginleştirmektir.

Üçüncü problem, dosyayı okuma işlemi başarısız olduğunda bir hata mesajı yazdırmak için expect kullandık, ancak hata mesajı sadece Dosyayı okumalıydı yazmaktadır. Bir dosya okumak birçok şekilde başarısız olabilir: örneğin, dosya eksik olabilir ya da açma iznimiz olmayabilir. Şu anda, duruma bakılmaksızın her şey için aynı hata mesajını yazdırmış oluyoruz; bu da kullanıcıya herhangi bir bilgi vermiyor!

tehlike

Dördüncü olarak, bir hatayı ele almak için expect kullanıyoruz ve kullanıcı programımızı yeterli argüman belirtmeden çalıştırırsa, Rust'tan indeks sınır dışı hatası alacaklardır; bu da problemi net bir şekilde açıklamıyor.

Tüm hata yönetim kodunun tek bir yerinde bulunması en iyi seçenek olacaktır, böylece gelecekteki bakım yapanlar bu kodla yalnızca bir yerde danışabilirler; tüm hata yönetim kodunun tek bir yerde tutulması, son kullanıcılar için anlamlı olacak mesajlar yazdırdığımızı da garanti edecektir.

Bu dört problemi, projemizi yeniden yapılandırarak ele alalım.


İkili Projeler İçin Endişelerin Ayrılması

main fonksiyonuna çoklu görevlerin sorumluluğunu atama organizasyonel problemi, birçok ikili projede yaygındır. Sonuç olarak, Rust topluluğu main büyümeye başladığında bir ikili programın ayrı endişelerini ayırmak için kılavuzlar geliştirmiştir. Bu sürecin şu adımları vardır:

  • Programınızı bir main.rs dosyasına ve bir lib.rs dosyasına ayırın ve programınızın mantığını lib.rs'ye taşıyın.
  • Komut satırı ayrıştırma mantığınız küçük olduğu sürece, main.rs içinde kalabilir.
  • Komut satırı ayrıştırma mantığı karmaşıklaşmaya başladığında, bunu main.rs'den çıkarın ve lib.rs'ye taşıyın.

Bu işlem sonrasında main fonksiyonunda kalacak olan sorumluluklar aşağıdaki ile sınırlı olmalıdır:

  • Argüman değerleriyle komut satırı ayrıştırma mantığını çağırmak
  • Diğer yapılandırmaları ayarlamak
  • lib.rs içinde bir run fonksiyonunu çağırmak
  • run bir hata döndürürse hatayı işlemek

Bu desen, endişelerin ayrılmasıyla ilgilidir: main.rs programı çalıştırma ile ilgilenirken, lib.rs mevcut görevle ilgili tüm mantığı yönetir.
— Rust Kılavuzları

main fonksiyonunu doğrudan test edemeyeceğiniz için, bu yapı, programınızın mantığını lib.rs içindeki fonksiyonlara taşımak suretiyle test etmenizi sağlar. main.rs içinde kalan kod, doğruluğunu okumakla doğrulamak için yeterince küçük olacaktır. Bu süreci izleyerek programımızı yeniden yapılandıralım.

Argüman Ayrıştırıcısını Çıkarma

Argümanları yorumlama işlevselliğini, komut satırı ayrıştırma mantığını src/lib.rs'ye taşımak için main'in çağıracağı bir fonksiyona çıkaracağız. Listing 12-5, şu an src/main.rs içinde tanımlayacağımız yeni bir parse_config fonksiyonunu çağıran main'in yeni başlangıcını göstermektedir.

{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-05/src/main.rs:here}}

Komut satırı argümanlarını bir vektörde toplamaya devam ediyoruz, ancak main fonksiyonu içinde indeks 1'deki argüman değerini query değişkenine ve indeks 2'deki argüman değerini file_path değişkenine atamak yerine, bütün vektörü parse_config fonksiyonuna iletiyoruz. parse_config fonksiyonu, hangi argümanın hangi değişkende yer alacağını belirleyen mantığı bulundurur ve değerleri geri main'e iletir. Hala main içinde query ve file_path değişkenlerini oluşturuyoruz, ancak main artık komut satırı argümanları ve değişkenleri arasındaki ilişkiyi belirlemekten sorumlu değildir.

bilgi

Bu yeniden yapılandırma, küçük programımız için aşırı gibi görünse de, küçük ve kademeli adımlarla yeniden yapılandırma yapıyoruz. Bu değişikliği yaptıktan sonra, argüman ayrıştırmanın hala çalıştığını doğrulamak için programı tekrar çalıştırın. İlerleme durumunuzu sık sık kontrol etmek, sorunlar ortaya çıktığında nedenini belirlemeye yardımcı olur.

Yapılandırma Değerlerini Gruplama

parse_config fonksiyonunu daha da geliştirmek için bir başka küçük adım atabiliriz. Şu anda bir demet (tuple) döndürüyoruz, ancak ardından hemen bu demeti tekrar bireysel parçalara ayırıyoruz. Bu, muhtemelen uygun soyutlamamızın henüz mevcut olmadığının bir işareti.

ipucu

Geliştirilecek bir alan olduğunu gösteren diğer bir gösterge, parse_config içindeki config kısmıdır; bu, döndürdüğümüz iki değerin ilişkili olduğunu ve her ikisinin de bir yapılandırma değerinin parçası olduğunu ima eder.

Şu anda bu anlamı, iki değeri bir demete gruplamak dışında veri yapısının içinde iletmiyoruz; bunun yerine iki değeri bir yapı (struct) içine koyup, her bir yapı alanına anlamlı bir isim vereceğiz. Bunu yapmak, bu kodun gelecekteki bakımcılarının farklı değerlerin nasıl ilişkilendiğini ve ne amaçla kullanıldığını anlamasını kolaylaştıracaktır.

Listing 12-6, parse_config fonksiyonundaki iyileştirmeleri göstermektedir.

{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-06/src/main.rs:here}}

query ve file_path adında alanlara sahip olan Config adı verilen bir yapı ekledik. parse_config imzası artık bir Config değeri döndürdüğünü belirtiliyor. parse_config'in içinde, daha önceden args içindeki String değerlerine referans veren string dilimlerini döndürdüğümüz yerde, şimdi Config'in sahip olduğu String değerleri içermesini tanımlıyoruz. main içindeki args değişkeni argüman değerlerinin sahibidir ve sadece parse_config fonksiyonunun onlara ödünç vermesine izin verir; bu da demektir ki, Config args içindeki değerlere sahip olmaya çalışırsa Rust'ın ödünç verme kurallarını ihlal etmiş olur.

String verisini yönetmenin birçok yolu vardır; en kolay, ancak biraz verimsiz olan yol, değerlerin üzerinde clone metodunu çağırmaktır. Bu, Config örneği için verilerin tam bir kopyasını alır; bu da, string verisine bir referans saklamaktan daha fazla zaman ve bellek harcar. Ancak verileri klonlamak, referansların yaşam döngülerini yönetmek zorunda olmadığımız için kodumuzu oldukça basit hale getirir; bu durumda, biraz performans kaybı karşılığında sadelik elde etmek kabul edilebilir bir değişimdir.

clone Kullanmanın Dezavantajları

Birçok Rust geliştiricisi, sahiplik problemlerini düzeltmek için clone kullanmakta tereddüt ederler çünkü bu, çalışma zamanı maliyetiyle ilişkilidir. 13. Bölümde, bu tür durumlarda daha verimli yöntemler kullanmayı öğreneceksiniz. Ancak şu anda, ilerlemeye devam etmek için birkaç string kopyalamak kabul edilebilir çünkü bu kopyaları ancak bir kez yapacaksınız ve dosya yolunuz ile sorgu stringiniz oldukça küçüktür. — Rust Geliştirme Kılavuzları

İlk seferde kodunuzu aşırı optimize etmeye çalışmaktansa, biraz verimsiz çalışan bir programa sahip olmak daha iyidir. Rust ile daha deneyimli hale geldikçe, en verimli çözümlerle başlamanız daha kolay olacak; ancak şu anda clone çağrısını yapmak tamamen kabul edilebilir.

main'i güncelleyerek parse_config tarafından döndürülen Config örneğini config adında bir değişkene koyduk ve daha önce ayrı query ve file_path değişkenlerini kullanan kodu, bunun yerine Config yapısındaki alanları kullanacak şekilde güncelledik.

bilgi

Artık kodumuz, query ve file_path'ın ilişkili olduğunu ve amacının programın nasıl çalışacağını yapılandırmak olduğunu daha net bir şekilde iletebiliyor. Bu değerleri kullanan her kod, config örneğinde, amaçlarıyla adlandırılan alanlardan bulmaları gerektiğini bilir.

Config için Bir Kurucu Oluşturma

Şu ana kadar, komut satırı argümanlarını ayrıştırma görevini main'den çıkardık ve parse_config fonksiyonuna koyduk. Bunu yapmak, query ve file_path değerlerinin ilişkili olduğunu görmemizi sağladı ve bu ilişkinin kodumuzda iletilmesi gerektiğini ortaya koydu. Sonra, query ve file_path'ın ilişkili amacını adlandırmak ve bu değerlerin adlarını parse_config fonksiyonundan döndürebilmek için Config yapısını ekledik.

Artık parse_config fonksiyonunun amacının bir Config örneği oluşturmak olduğunu bildiğimizden, parse_config'i sıradan bir fonksiyondan, Config yapısıyla ilişkili bir new adlı bir fonksiyona dönüştürebiliriz. Bu değişiklik, kodun daha idiyomatik olmasını sağlayacaktır. Standart kütüphanedeki türlerin (örneğin, String) örneklerini String::new çağrısı yaparak oluşturabiliriz; benzer şekilde, parse_config'i Config ile ilişkili bir new fonksiyonu haline getirerek, Config örneklerini Config::new ile oluşturabileceğiz. Listing 12-7, yapmamız gereken değişiklikleri göstermektedir.

{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-07/src/main.rs:here}}

parse_config'i çağırdığımız main'i güncelleyerek, bunun yerine Config::new çağırıyoruz. parse_config'in adını new olarak değiştirdik ve bunu new fonksiyonunu Config ile ilişkilendiren bir impl bloğu içine taşıdık. Bu kodun yine çalıştığını derlemeyi deneyin.

Hata Yönetimini Düzeltme

Artık hata yönetimimizi düzeltmeye çalışacağız. args içindeki 1. veya 2. indekslerdeki değerlere erişmeye çalışmak, vektör üçten az öğe içeriyorsa programın paniklemesine neden olacaktır. Herhangi bir argüman olmadan programı çalıştırmayı deneyin; bu şöyle görünür:

{{#include ../listings/ch12-an-io-project/listing-12-07/output.txt}}

indeks sınır dışı: uzunluk 1 ama indeks 1 satırı, programcılar için tasarlanmış bir hata mesajıdır. Bu, son kullanıcılarımızın ne yapmaları gerektiğini anlamalarına yardımcı olmayacaktır. Şimdi bunu düzeltelim.

Hata Mesajını İyileştirme

Listing 12-8'de, indeks 1 ve indeks 2'ye erişmeden önce dilimin yeterince uzun olduğunu doğrulayan bir kontrol ekliyoruz. Dilim yeterince uzun değilse, program panikler ve daha iyi bir hata mesajı görüntüler.

{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-08/src/main.rs:here}}

Bu kod, Listing 9-13'te yazdığımız Guess::new fonksiyonuna benzer9, burada value argümanı geçerli değerler aralığının dışında olduğunda panic! çağrısında bulunmuştuk. Burada geçerli değerler aralığı kontrol etmek yerine, args uzunluğunun en az 3 olduğunu kontrol ediyoruz ve fonksiyonun geri kalan kısmı bu koşulun sağlandığı varsayımı altında işleyecek. Eğer args, üçten az öğe içeriyorsa, bu koşul true olacaktır ve programı hemen sonlandırmak için panic! makrosunu çağırıyoruz.

new içindeki bu birkaç ekstra satır ile, programı yine herhangi bir argüman olmadan çalıştırmayı deneyelim ve şimdi hatanın nasıl göründüğüne bakalım:

{{#include ../listings/ch12-an-io-project/listing-12-08/output.txt}}

Bu çıktı daha iyi: şimdi makul bir hata mesajımız var. Ancak, kullanıcılara vermek istemediğimiz gereksiz bilgiler de var. Belki Listing 9-13'te kullandığımız teknik burada en iyi seçim değildir: panic! çağrısı, bir programlama problemi için daha uygundur, kullanım problemi için değil. 9. Bölümde tartışıldığı gibi, bunun yerine üzerinde konuştuğunuz diğer teknik kullanılan ifade mümkün olan bir Result döndürmek olacaktır9; bu, ya başarı ya da hata olarak tanımlanabilir.


panic! Çağırmak Yerine Result Döndürmek

Bunun yerine, başarılı durumda bir Config örneği ve hata durumunda problemi tanımlayan bir Result değeri döndürebiliriz. Ayrıca, new fonksiyon adını build olarak değiştireceğiz çünkü birçok programcı new fonksiyonlarının asla başarısız olmalarını bekler. Config::build main ile iletişim kurduğunda, sorun olduğuna işaret etmek için Result türünü kullanabiliriz. Ardından, main'i Err varyantını kullanıcılar için daha pratik bir hata mesajına dönüştürmek için değiştirebiliriz; böylece thread 'main' ve RUST_BACKTRACE gibi panic! çağrısının oluşturduğu etrafındaki metinler ortadan kalkacaktır.

Listing 12-9, artık Config::build olarak adlandırdığımız fonksiyonun dönüş değerinde yapmamız gereken değişiklikleri ve Result döndürmek için gerekli olan fonksiyonun gövdesini göstermektedir. Bu, main'i de güncellemediğimiz sürece derlenmeyecek.

{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-09/src/main.rs:here}}

build fonksiyonumuz, başarı durumunda bir Config örneği ve hata durumunda bir string literal içeren bir Result döndürür. Hata değerlerimiz her zaman 'static ömrüne sahip string literaller olacaktır.

Fonksiyon gövdesinde iki değişiklik yaptık: kullanıcı yeterli argüman geçmediğinde panic! çağırmak yerine, artık bir Err değeri döndürüyoruz ve Ok ile Config döndürme değerini sarmaladık. Bu değişimler, fonksiyonun yeni tür imzasına uyum sağlamasını sağlamaktadır.

Config::build'den bir Err değeri döndürmek, main fonksiyonuna, build fonksiyonundan döndürülen Result değerini ele alacak ve hata durumunda süreci daha temiz bir şekilde sonlandırmasına olanak tanır.


Config::build'i Çağırmak ve Hataları Ele Almak

Hata durumunu ele almak ve kullanıcı dostu bir mesaj yazdırmak için, main'i Config::build tarafından döndürülen Result değerini ele alacak şekilde güncellememiz gerekecek; bu, Listing 12-10'da gösterildiği gibi. Ayrıca, komut satırı aracının sıfırdan farklı bir hata kodu ile çıkma sorumluluğunu panic!'den alıp buna manuel olarak gerçekleştireceğiz. Sıfırdan farklı bir çıkış durumu, programımızın hata durumu ile çıktığını belirtmek için bir gelenektir.

{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-10/src/main.rs:here}}

Bu listedeki kod, henüz ayrıntılı olarak ele almadığımız bir yöntemi içermektedir: unwrap_or_else, bu yöntem Result üzerine standart kütüphane tarafından tanımlanmıştır. unwrap_or_else kullanmak, özel bir panic! dışı hata yönetimi tanımlamamıza olanak sağlar. Result bir Ok değeri ise, bu yöntem davranışı unwrap ile benzerdir: Ok'ın sarmaladığı iç değeri döndürür. Ancak, değer bir Err değeri ise, bu yöntem, argüman olarak geçirdiğimiz kapsayıcıdaki kodu çağırır; bu kod, hata durumunda çalışacak olan anonim bir fonksiyondur. Kapsayıcıyı daha ayrıntılı inceleyeceğiz 13. Bölümde. Şimdilik unwrap_or_else'in Err iç değerini, bu durumda Listing 12-9'da eklediğimiz statik string olan "yeterli argüman yok" değerini, err argümanına geçeceğini bilmeniz yeterlidir. Kapsayıcıdaki kod, çalıştığında err değerini kullanabilir.

Yeni bir use satırı ekleyerek process'i standart kütüphaneden kapsam içine aldık. Hata durumunda çalışacak olan kapsayıcıdaki kod, yalnızca iki satırdır: err değerini yazdırıyoruz ve ardından process::exit çağırıyoruz. process::exit fonksiyonu programı derhal durduracak ve çıkış durumu olarak belirttiğimiz sayıyı döndürecektir. Bu, Listing 12-8'de kullandığımız panic!-temelli yönetimle benzerlik göstermektedir; ancak artık tüm ekstra çıktıyı almayacağız. Hadi deneyelim:

{{#include ../listings/ch12-an-io-project/listing-12-10/output.txt}}

Harika! Bu çıktı kullanıcılarımız için çok daha dostça.

main'den Mantığı Çıkarma

Artık yapılandırma ayrıştırmasını yeniden yapılandırmayı bitirdiğimize göre, programın mantığına dönelim. Yukarıda bahsedildiği gibi“İkili Projeler İçin Endişelerin Ayrılması”, main fonksiyonunda yapılandırmayla veya hata yönetimiyle ilgili olmayan tüm mantığı tutacak bir run fonksiyonu çıkarmayı planlıyoruz. İşim bittiğinde main, iç gözlemle doğrulaması kolay ve özlü olacak ve tüm diğer mantık için test yazabileceğiz.

Listing 12-11, çıkarılan run fonksiyonunu göstermektedir. Şu an için yalnızca fonksiyonu çıkarmanın küçük, kademeli iyileştirmesini yapıyoruz. Fonksiyonu hâlâ src/main.rs içinde tanımlıyoruz.

{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-11/src/main.rs:here}}

run fonksiyonu artık main'den okuma işlemi ile başlayan tüm geri kalan mantığı içermektedir. run fonksiyonu, Config örneğini argüman olarak alır.

run Fonksiyonundan Hata Döndürme

Kalan program mantığı run fonksiyonuna ayrıldığında, Config::build ile yaptığımız gibi hata yönetimini geliştirebiliriz. Programın expect çağrısı yaparak panik yapmasını sağlamak yerine, run fonksiyonu bir şeyler ters gittiğinde Result döndürecektir. Bu, hata yönetimine dair mantığı main içinde kullanıcı dostu bir şekilde daha da konsolide etmemize olanak tanıyacak.

ipucu

Değişiklikleri göstermek için 12-12 numaralı listedeki imzaya ve run fonksiyonunun gövdesine gereken değişiklikleri yaptık.

{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-12/src/main.rs:here}}

Burada üç önemli değişiklik yaptık. İlk olarak, run fonksiyonunun dönüş tipini Result> olarak değiştirdik. Bu fonksiyon daha önceden birim tipini, (), döndürüyordu ve bu değeri Ok durumunda geri döndürmeye devam ediyoruz.

bilgi

Hata tipi için trait nesnesi olan Box kullandık (ve std::error::Error'ı en üstteki bir use deklarasyonu ile kapsamımıza aldık). Trait nesnelerini Bölüm 18'de ele alacağız.

İkincisi, hata durumunda panic! yerine ? operatörünü kullanarak expect çağrısını kaldırdık. Bölüm 9'de konuştuğumuz gibi.

panic! yerine ? kullanmak, mevcut fonksiyondan hata değerini döndürecektir, bu da çağıran tarafından yönetilecektir. — Dökümantasyon

Üçüncüsü, run fonksiyonu artık başarı durumunda bir Ok değeri döndürüyor.

not

run fonksiyonunun başarı tipini imzada () olarak belirledik, bu da birim tip değerini Ok değeri içinde sarmamız gerektiği anlamına geliyor. Bu Ok(()) sözdizimi başlangıçta biraz garip görünse de, böyle kullanmak run fonksiyonunu yalnızca yan etkileri için çağırdığımızı belirtmenin deyimsel yoludur; döndürdüğü bir değer yok.

Bu kodu çalıştırdığınızda, derlenecek ancak bir uyarı gösterecektir:

{{#include ../listings/ch12-an-io-project/listing-12-12/output.txt}}

Rust, kodumuzun Result değerini göz ardı ettiğini ve bu Result değerinin bir hata meydana geldiğini gösterebileceğini söyler. Ancak bir hata olup olmadığını kontrol etmiyoruz ve derleyici burada bazı hata yönetim kodları eklemeyi kastettiğimizi hatırlatıyor! Şimdi bu sorunu güncelleyelim.

main İçinde run'dan Dönen Hataları Yönetme

Hata kontrolü yapacağız ve bunu, 12-10 numaralı listede Config::build ile kullandığımız benzer bir teknik ile ele alacağız, ancak ufak bir farklılık ile:

Dosya Adı: src/main.rs

{{#rustdoc_include ../listings/ch12-an-io-project/no-listing-01-handling-errors-in-main/src/main.rs:here}}
tehlike

run'ın bir Err değeri döndürüp döndürmediğini kontrol etmek ve dönerse process::exit(1) çağırmak için if let kullanıyoruz.

run fonksiyonu, Config::build'in Config örneğini döndürdüğü gibi unwrap etmek istediğimiz bir değer döndürmüyor. Çünkü run, başarı durumunda () döndürüyor, bu nedenle sadece bir hata tespit etme ile ilgileniyoruz; bu yüzden unwrap_or_else'in sarmalanmış değeri döndürmesine gerek yok, bu yalnızca () olacaktı.

Her iki durumda da if let ve unwrap_or_else fonksiyonlarının gövdeleri aynıdır: hatayı yazdırıyoruz ve çıkıyoruz.


Kodu Bir Kütüphane Krate'ine Ayırma

minigrep projemiz şu ana kadar iyi görünüyor! Şimdi src/main.rs dosyasını ayıracağız ve bazı kodları src/lib.rs dosyasına koyacağız. Böylece kodu test edebilir ve daha az sorumluluk ile bir src/main.rs dosyası edinebiliriz.

ipucu

main fonksiyonu içinde bulunmayan tüm kodları src/main.rs'dan src/lib.rs'ya taşımalıyız:

  • run fonksiyonu tanımı
  • İlgili use deklarasyonları
  • Config tanımı
  • Config::build fonksiyonu tanımı

src/lib.rs'in içerikleri, kısalık nedeniyle fonksiyonların gövdelerini hariç tutarak, 12-13 numaralı listedeki imzalara sahip olmalıdır. Bu, 12-14 numaralı listedeki src/main.rs dosyasını değiştirmeden derlenmeyecek.

{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-13/src/lib.rs:here}}
not

pub anahtar kelimesini cömertçe kullandık: Config, alanları ve build metodu üzerinde ve run fonksiyonu üzerinde. Artık test edebileceğimiz kamuya açık bir API'ye sahip bir kütüphane krate'imiz var!

Şimdi src/lib.rs'da hareket ettirdiğimiz kodu src/main.rs içindeki ikili krate'in kapsamına almak gerekiyor, bu 12-14 numaralı listedekine benzer bir şekilde.

{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-14/src/main.rs:here}}

Config türünü kütüphane krate'indan ikili krate'in kapsamına almak için use minigrep::Config satırını ekliyoruz ve run fonksiyonunu krate adımızla önekliyoruz.

tehlike

Şimdi tüm işlevsellik bağlantılı olmalı ve çalışmalıdır. Programı cargo run ile çalıştırın ve her şeyin doğru çalıştığından emin olun.

Uff! Bu çok işti, ama kendimizi gelecekte başarıya ulaşmaya hazırladık. Artık hataları yönetmek çok daha kolay ve kodumuzu daha modüler hale getirdik. Bundan sonra işimizin çoğunu src/lib.rs içinde yapacağız.

Eski kod ile zor olacak ama yeni kod ile kolay olacak bu yeni modülerlikten faydalanalım: bazı testler yazalım!