İçeriğe geç
academia.sh

Ders 12 / 12

Modüller ve Kasalar

mod ve use birer öğedir: hiçbiri tek başına bir değer üretmez, biri bir ad sınırı çizer, öbürü var olan bir yolu kısaltır. Aynı ad hem modülün içinden hem dışından çağrılıyor ve pub yazılan/yazılmayan hâller karşılaştırılıyor; iki ayrı kaynak dosyası tek bir rustc çağrısıyla derlenip tek bir kasa oluşturuyor. Sınırlayıcı ölçüm görünürlüğün yolun her halkasında ayrı sağlanması gerektiğini gösteriyor: bir öğe pub olsa bile onu saran modül pub değilse dışarıdan erişilemez.

Yayın Güncelleme

Bu derste

  • mod ve use bildirimlerinin birer öğe olduğunu ve tek başına değer üretmediğini gösterir
  • Aynı adın modül içinden ve dışından çağrılmasını pub yazılan ve yazılmayan hâllerle karşılaştırır
  • Bir modülün kasadan farkını iki kaynak dosyasının tek bir derleme biriminde birleşmesiyle ölçer
İçindekiler

Beş veri modelleme dersi kapandı ve hep aynı soruyu sordu: kaynakta yazılan bir şey bir değer mi üretiyor? Bu soru hiçbir yerde, bir tipin ya da bir fonksiyonun kaynağın neresinde göründüğüne değinmedi — bir yapı bildirimi, bir sözlük değişkeni, bir işlev, hangi sınırın içinde tanımlı ve o sınırın dışından nasıl görülüyor? Kurulum ve Paket Yöneticisi dersi bu soruyu bir kez ertelemişti: kaynak kökünün gerçek bir projede tek bir dosya olmadığını, derleyicinin oradan başlayıp başka dosyalara mod bildirimleriyle ulaştığını söylemiş, ama göstermemişti. Bu ders — kursun kapanışı — o ertelenen soruyu açıyor: mod ve use birer değer mi üretiyor, yoksa yalnızca bir sınır mı çiziyor; ve bir modülün sınırı ile bir kasanın sınırı aynı şey mi?

mod Bir Sınır Çizer, Kendisi Değer Üretmez

Rust’ın Tasarım Hedefleri dersinde mod olcu { pub fn birim() -> i32 { 3 } } biçiminde bir modül zaten görülmüştü ve o dersin ölçüm çekirdeği mod bildirimini bir öğe saymıştı — ama üstünde durmamıştı. Bu ders tam orada duruyor: mod ad { ... } satırı çalıştırıldığında hiçbir şey üretmez. Yapılar dersindeki struct bildirimi gibi, derleyiciye bir ad ve bir sınır tanıtır, kendisi değerlendirilmez. İçindeki her öğe — fonksiyon, sabit, başka bir modül — ancak kullanıldığında bir değer doğurur.

// mod_ic_dis.rs — mod bir oge, ayni ad hem modul icinden hem disindan cagriliyor
mod olcum {
    pub fn birim() -> i32 {
        3
    }

    fn ozel_carpan() -> i32 {
        10
    }

    pub fn buyutulmus() -> i32 {
        birim() * ozel_carpan()
    }
}

fn main() {
    let disaridan = olcum::birim();
    println!("{:<32}: {}", "olcum::birim() (pub, distan)", disaridan);

    let ictekinden = olcum::buyutulmus();
    println!("{:<32}: {}", "olcum::buyutulmus() (pub, distan)", ictekinden);
}
olcum::birim() (pub, distan)    : 3
olcum::buyutulmus() (pub, distan): 30

RV20. olcum modülünün bildirimi hiçbir satırda çalışmadı; görülen iki çıktı da birim ve buyutulmusün çağrıldığı satırlardan geldi. birim adı burada iki ayrı konumdan çağrılıyor: main içinden olcum::birim() olarak — modülün dışından, tam yolla — ve buyutulmusün gövdesinden birim() olarak — modülün içinden, hiçbir önek gerekmeden. Aynı ad, aynı öğe, iki farklı konumdan aynı değeri (3) üretiyor; değişen yalnızca çağıranın modül sınırının hangi tarafında durduğu.

ozel_carpan fonksiyonu pub taşımadan bildirildi ve yalnızca buyutulmusün gövdesinden, yani olcum modülünün kendi içinden çağrılabildi. Bu, Rust’ta görünürlüğün varsayılan olarak kapalı olduğunu gösteriyor: bir öğe, tanımlandığı modülün dışından, tek bir anahtar sözcük — pub — eklenmeden görünmez. birim ile buyutulmus bu anahtar sözcüğü taşıdığı için mainden erişilebildi; ozel_carpan taşımadığı için erişilemedi. Eğer main içine olcum::ozel_carpan() yazılsaydı, bu satır derlenmezdi. Bu ret burada kod bloğuna konmuyor — Desen Eşleme dersinde kurulan kuralla aynı gerekçeyle, derlenmeyen kaynak bloğa girmiyor — ama nedeni tarif edilebilir: derleyici, çağrının pub taşımayan bir öğe üzerinden modül sınırını geçmeye çalıştığını görür ve kaynağı reddeder.

Dosya Sınırı Modül Sınırına Dönüşür — Kasa Tek Derleme Birimidir

Kurulum ve Paket Yöneticisi dersi, kaynak kökünün bu kursta hep tek bir dosya olduğunu, ama gerçek bir projede derleyicinin oradan başlayıp başka dosyalara mod bildirimleriyle ulaştığını söylemişti. Burada gösteriliyor: mod ad; yazımı — gövdesiz, yalnızca noktalı virgülle biten hâli — derleyiciye aynı dizindeki ad.rs dosyasını okumasını ve o dosyanın tamamını ad adlı modülün gövdesi saymasını söylüyor.

// yardimci.rs — mod adi ile cekilen dosyanin tamami modulun govdesidir (KAYNAK)
pub fn disaridan_gorunur() -> i32 {
    ozel_sabit() + 5
}

fn ozel_sabit() -> i32 {
    100
}
// mod_dosya_siniri.rs — mod yardimci; bir dosya sinirini modul sinirina cevirir
mod yardimci;

fn main() {
    let deger = yardimci::disaridan_gorunur();
    println!("{:<34}: {}", "yardimci::disaridan_gorunur()", deger);
}
yardimci::disaridan_gorunur()     : 105

RV21. Bu ölçümde iki ayrı kaynak dosyası var — mod_dosya_siniri.rs ve yardimci.rs — ama derleme komutu bir kez çalıştı ve tek bir ikili üretti: iki dosya, bir kasa. Bu tek derleme biriminin adı kasadır (crate): rustce verilen tek bir kaynak kökünden başlayıp mod ile ulaşılan bütün dosyaların bir araya gelmesiyle oluşan, tek bir derleme adımından geçen bütün. yardimci.rs içindeki ozel_sabit fonksiyonu pub taşımıyor; önceki bölümdeki kuralın aynısı burada da geçerli — ozel_sabit, yalnızca yardimci modülünün kendi içinden, yani disaridan_gorunurün gövdesinden çağrılabiliyor.

Modül ile kasa burada birbirine karışabilir, çünkü ikisi de bir sınır çiziyor, ama çizdikleri sınırlar farklı düzlemde. Modül bir isim ve görünürlük sınırıdır; kaynağın tek bir dosyada mı yoksa on dosyada mı durduğuyla ilgilenmez — önceki bölümdeki olcum bunu tek dosyanın içinde gösterdi. Kasa ise bir derleme ve bağlama sınırıdır: kaç dosyadan, kaç modülden oluşursa oluşsun, tek bir rustc çağrısından geçen her şey aynı kasanın parçasıdır. Bir kasa birden çok modül taşıyabilir — mod_dosya_siniri.rs kaynak kökü ile yardimci modülü burada aynı kasanın iki parçasıydı — ama bir modül asla birden çok kasaya bölünmez.

use Bir Öğedir: Kısayolun Kendisi Değer Üretmez

modun çizdiği sınır bir kez kurulduktan sonra, o sınırın içindeki bir adı her seferinde tam yoluyla (olcum::birim()) yazmak zorunlu değildir. use bildirimi bir yolu kısaltan bir addır ve tıpkı mod gibi bir öğedir: satırın kendisi hiçbir değer üretmez, yalnızca sonraki satırların kullanabileceği kısa bir ad tanıtır.

// use_oge.rs — use bir oge, deger ancak kisayoldan gelen ad kullaninca dogar
mod olcum {
    pub fn birim() -> i32 {
        3
    }
}

use olcum::birim;

fn main() {
    let kisayoldan = birim();
    let tam_yoldan = olcum::birim();
    println!("{:<30}: {}", "birim() (use sonrasi kisayol)", kisayoldan);
    println!("{:<30}: {}", "olcum::birim() (tam yol)", tam_yoldan);
    println!("{:<30}: {}", "esit mi", kisayoldan == tam_yoldan);
}
birim() (use sonrasi kisayol) : 3
olcum::birim() (tam yol)      : 3
esit mi                       : true

RV22. use olcum::birim; satırı mainden önce duruyor ve hiçbir çıktı doğrudan ona bağlı değil — tıpkı bir önceki bölümdeki mod yardimci; gibi, kendisi çalıştırılmıyor. İki çağrı da — kısayoldan birim() ve tam yoldan olcum::birim() — aynı değeri (3) üretiyor; esit mi satırı bunu doğrudan doğruluyor. use bir kısayol tanıtıyor, yeni bir hesaplama ya da yeni bir davranış değil: kısayoldan gelen değer ile tam yoldan gelen değer arasında hiçbir fark yok, çünkü ikisi de aynı öğeye, olcum::birime, işaret ediyor. Bu, bir önceki bölümdeki bulguyla aynı ailededir — bir bildirim kaynağa yeni bir hesaplama eklemez, yalnızca sonraki satırların okuyabileceği bir ad ekler; mod bunu bir sınır için yapar, use aynısını var olan bir sınırın içindeki bir yol için yapar.

Sınırlayıcı Ölçüm: Görünürlük Yolun Her Halkasında Ayrı Sağlanır

Buraya kadarki iki ölçüm görünürlüğü tek bir düzeyde gösterdi: bir öğe ya modülün dışına pub taşıyordu ya taşımıyordu. Gerçek sınır bundan biraz daha ince: bir öğe pub olsa bile, onu saran modül pub değilse, dışarıdan o öğeye ulaşılamaz.

// gorunurluk_zinciri.rs — gorunurluk yolun her halkasinda ayri ayri saglanmali
mod dis {
    pub mod ic {
        pub fn deger() -> i32 {
            gizli() + 1
        }

        fn gizli() -> i32 {
            6
        }
    }
}

fn main() {
    let sonuc = dis::ic::deger();
    println!("{:<30}: {}", "dis::ic::deger() (iki pub halka)", sonuc);
}
dis::ic::deger() (iki pub halka): 7

RV23. dis::ic::deger() çağrısı derlendi ve 7 verdi, çünkü yoldaki iki halka da — ic modülü ve deger fonksiyonu — pub taşıyor; disin kendisi pub taşımıyor ama zaten kaynak kökünün kendi düzeyinde tanımlı olduğu için dışarıdan (bu dosyanın kendisinden) görünür durumda. Eğer ic modülü pub olmadan yalnızca mod ic { ... } yazılsaydı, deger fonksiyonunun kendisi hâlâ pub kalsa bile dis::ic::deger() çağrısı derlenmezdi — çünkü yol, pub taşımayan bir modül sınırından geçmek zorunda kalırdı. Bu kaynak da kod bloğuna konmuyor, aynı derlenmeyen-kaynak kuralıyla; ama sonucu tarif edilebilir: derleyici için tek bir öğenin görünürlüğü yetmiyor, yoldaki her adımın görünürlüğü ayrı ayrı sağlanmalı.

Bu, kursun kendi kapanışının sınırıdır da. Buradaki üç ölçüm — tek düzeyli pub/private karşıtlığı, dosya sınırının modül sınırına dönüşmesi, çok halkalı görünürlük zinciri — görünürlüğü ikili (açık ya da kapalı) bir anahtar gibi ele aldı. Rust’ın sunduğu ara dereceler — yalnızca kasaya açık, yalnızca üst modüle açık gibi — bu derste hiç ölçülmedi, çünkü ölçü ekseni hâlâ aynı soruydu: kaynakta yazılan bu şey bir değer mi üretiyor. Kaynakta yazılan pub ile pub olmayan arasındaki fark tek bir ikili yanıt üretti; bu ikili yanıtın kendi içindeki ince dereceler, bu eksenin dışında kalan ayrı bir konu.

Özet

  • mod bildirimi bir öğedir: kendisi değer üretmez, yalnızca bir ad ve bir sınır tanıtır; aynı ad modülün içinden öneksiz, dışından tam yolla çağrılabilir.
  • Görünürlük varsayılan olarak kapalıdır; tek bir pub anahtar sözcüğü bir öğeyi modülün dışına açar.
  • mod ad; yazımı bir dosya sınırını modül sınırına çevirir; birden çok kaynak dosyası tek bir rustc çağrısında derlenip tek bir kasa oluşturabilir.
  • use bir öğedir: bir yolu kısaltan bir ad tanıtır, kendisi hiçbir değer üretmez; kısayoldan ve tam yoldan çağrılan aynı öğe aynı değeri verir.
  • Görünürlük yolun her halkasında ayrı sağlanmalıdır: bir öğe pub olsa bile onu saran bir modül pub değilse dışarıdan erişilemez.

Kurs Kapanışı

Bu kurs, on iki ders boyunca tek bir soruyu sürdürdü: kaynakta yazılan bir şey bir değer mi üretiyor, yoksa yalnızca bir ad mı bildiriyor? İlk altı ders bu soruyu dilin en küçük birimlerine — ifadelere, bağlamalara, temel tiplere, denetim akışına — sordu; sonraki beş ders aynı soruyu veri modelleme araçlarına — yapılara, numaralandırmalara, desen eşlemeye, koleksiyonlara, sıralı ve karma yapılara — taşıdı. Bu son ders, sorunun kendisini değiştirmeden, kaynağın neresinde göründüğü sorusunu ekledi: bir öğe hangi sınırın içinde tanımlı ve o sınırın dışından nasıl görülüyor?

On iki dersin her biri kendi kesitini ölçtü ve kendi sınırlayıcı ölçümünü yazdı; aşağıdaki tablo bu on iki ölçümü tek bir yerde topluyor.

Ders Ölçülen yazım Sınıfı (ifade · deyim · öğe) Sınırlayıcı ölçüm
Rust’ın Tasarım Hedefleri if/match bir dal seçip değer verir ifade Sınıf işin doğasından değil, yöntemin imzasından okunur (insert ifade, push deyim)
Kurulum ve Paket Yöneticisi giriş noktası, kaynak kökü, bildirim dosyası öğe Bildirim dosyası kaynağın içinde değil; kaynak değişmeden yalnız o dosya değişince çıktının adı değişir
Değişkenler ve Değişmezlik let bağlaması deyim Değişmezlik bağlamanın kendi sınırıdır; verinin başka yoldan paylaşılması ayrı bir soru (K02)
Temel Tipler beş temel tipten değer kurmak ifade () değersiz değil, tek değerli bir tiptir
Fonksiyonlar ve İfade Odaklılığı gövdenin son satırı (tail konumu) ifade Noktalı virgül değeri sessizce atar; hesaplama yine de gerçekleşir
Denetim Akışı elsesiz if ifade Değeri her zaman ()dir; gövdesi başka bir tip üretmeye kalkarsa derlenmez
Yapılar struct bildirimi öğe Demet yapısında sıra tek kimliktir; adlandırılmış yapıda alan sırası serbesttir
Numaralandırmalar enum bildirimi öğe Varyant sayısı durum sayısı değildir; veri taşıyan bir varyant sayılamayacak kadar durum taşır
Desen Eşleme match ifadesi ifade Bir yakalayıcı dal bütünlüğü sağlar ama korumaz: sonradan eklenen bir varyantı kendi mantığıyla ele almadan sessizce kapsar
Koleksiyonlar push / insert deyim · ifade insertin dönüş değeri bir değişkene bağlanmazsa, üzerine yazılan eski değer sessizce kaybolur
Sıralı ve Küme Yapıları küme ekleme (insert → bool) ifade Sıra güvencesi bir koşula bağlıdır: anahtar tipinin sıralanabilirlik koşulunu karşılaması gerekir
Modüller ve Kasalar mod bildirimi / use öğe Görünürlük yolun her halkasında ayrı sağlanır; bir öğe pub olsa bile onu saran modül değilse erişilemez

Üç sınıf — ifade, deyim, öğe — kursun başından sonuna kadar değişmedi; değişen yalnızca bu üç sınıfın uygulandığı yazımın genişliğiydi: tek bir satırdan bir fonksiyon gövdesine, bir veri tipinin bildiriminden bir modülün sınırına. Sahiplik ve ödünç alma bu kursta defalarca ertelendi — bir bağlamanın değişmezliği (Değişkenler ve Değişmezlik dersi), bir alıcının &self işareti (Yapılar dersi), bir referansın çift & işareti (Koleksiyonlar dersi) her seferinde bunun K02’nin konusu olduğu söylenerek geçildi. Sıradaki kurs bu ertelenen soruyu açıyor: bir değerin sahibi kimdir, bir referans ödünç almak ne demektir ve bir değer sahibinden ayrıldığında ne olur?

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ ↵ Esc gezin · aç · kapat