Ders 15 / 15
Dizileştirme
Bir yapının alanlarına elle yazılmış bir dönüşüm gövdesi uygulanırken bu gövdenin alan başına kaç kez koştuğunun, iç içe bir yapıda bu sayının nasıl çarpımsal büyüdüğünün ve ters yönde — metinden yapıya — bir alanın başarısızlığının sonraki alanların gövdesini hiç çalıştırmadığının ölçülmesi; kursun on beş dersinde ölçülen bütün gövdeler burada tek bir tabloda toplanıyor.
Yayın Güncelleme
Bu derste
- Bir yapının alanlarına uygulanan dönüşüm gövdesinin alan başına kaç kez koştuğunu ve iç içe bir yapıda bu sayının nasıl büyüdüğünü koşturarak gösterir
- Metinden yapıya çözümlemede bir alanın başarısızlığının sonraki alanların gövdesini hiç çalıştırmadığını ölçerek doğrular
- Kursun on beş dersinde ölçülen bütün gövdeleri sınıflarına göre bir kapanış tablosunda karşılaştırır
İçindekiler
Yineleyici Bağdaştırıcıları dersi, bir zincirin ucundaki tüketicinin kaynaktaki bir dönüşüm gövdesini kaç kez çağırdığını ölçtü — zincirin uzunluğu sabit kalırken koşan gövde sayısı tüketiciye göre değişiyordu. Bu kapanış dersi aynı soruyu somut bir veri biçimine taşıyor: bir yapının alanlarına uygulanan bir dönüşüm gövdesi, yapı serilirken alan başına kaç kez koşuyor. Burada zincirin elemanları artık bir dizinin girdileri değil, tek bir yapının alanları; tüketici de tektir — serileştirmenin kendisi. Dönüşüm bu derste elle yazılıyor, üçüncü taraf bir kasa kullanılmıyor; bir dizileştirme çerçevesi olsaydı bu gövdeyi kendisi üretirdi, ama burada gövde kaynakta görünür kalıyor ve sayılabiliyor. Kurs boyunca sorulan soru burada da değişmiyor: kaynakta yazdığın bu gövde kaç kez koştu? Bu, kursun on beşinci ve son dersi; kapanışında on dört dersin tamamında ölçülen gövdeler tek bir tabloda toplanacak.
Alan Başına Koşan Dönüşüm Gövdesi
Bir dizileştirme çerçevesi olsaydı bu dönüşümü kendisi üretir, alan sayısı arttıkça gövdeyi görünmez biçimde büyütürdü. Bu ders dönüşümü elle yazıyor: her alan, aynı yardımcı işlevden geçerek bir dizgeye çevriliyor ve bu geçiş her seferinde sayaç defterine bir kayıt düşüyor. Ölçüm çekirdeğinin bu kesiti yalnız sayma defterini taşıyor; trait, sınır ya da hata tipi bu derste kullanılmıyor.
// kere.rs — kesit: sayma defteri.
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;
pub type Defter = Rc<RefCell<BTreeMap<String, u32>>>;
pub fn say(defter: &Defter, ad: &str) {
*defter.borrow_mut().entry(ad.to_string()).or_insert(0) += 1;
}
pub fn kere(defter: &Defter, ad: &str) -> u32 {
*defter.borrow().get(ad).unwrap_or(&0)
}
Üç alanlı bir Nokta yapısı, alanlarını sırayla dizgeye çeviren bir dizilestir yöntemi
taşıyor; her alan aynı alani_yaz işlevinden geçiyor ve geçiş sayılıyor. Cizgi, iki Noktayı
birden taşıyan bir yapı; kendi dizilestiri kendi alanına dokunmuyor, taşıdığı iki Noktanın
dizilestirini çağırıyor. Ucgen, üç Cizgiyi taşıyan bir yapı; aynı örüntü bir kat daha
derine iniyor.
// alan-govdesi.rs — bir govdenin alan basina kac kez kostugunu olcer, ic ice buyumeyi gosterir.
mod kere;
use kere::{kere, say, Defter};
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;
fn alani_yaz(defter: &Defter, ad: &str, deger: i32) -> String {
say(defter, "alan-govdesi");
format!("{}={}", ad, deger)
}
struct Nokta {
x: i32,
y: i32,
z: i32,
}
impl Nokta {
fn dizilestir(&self, defter: &Defter) -> String {
let x = alani_yaz(defter, "x", self.x);
let y = alani_yaz(defter, "y", self.y);
let z = alani_yaz(defter, "z", self.z);
format!("{};{};{}", x, y, z)
}
}
struct Cizgi {
bas: Nokta,
bitis: Nokta,
}
impl Cizgi {
fn dizilestir(&self, defter: &Defter) -> String {
format!("{}|{}", self.bas.dizilestir(defter), self.bitis.dizilestir(defter))
}
}
struct Ucgen {
kenar1: Cizgi,
kenar2: Cizgi,
kenar3: Cizgi,
}
impl Ucgen {
fn dizilestir(&self, defter: &Defter) -> String {
format!(
"{}#{}#{}",
self.kenar1.dizilestir(defter),
self.kenar2.dizilestir(defter),
self.kenar3.dizilestir(defter)
)
}
}
fn main() {
let defter: Defter = Rc::new(RefCell::new(BTreeMap::new()));
let onceki = kere(&defter, "alan-govdesi");
let nokta = Nokta { x: 1, y: 2, z: 3 };
let _ = nokta.dizilestir(&defter);
let sonraki = kere(&defter, "alan-govdesi");
println!("Nokta (3 alan): {} govde kosumu", sonraki - onceki);
let onceki = sonraki;
let cizgi = Cizgi {
bas: Nokta { x: 0, y: 0, z: 0 },
bitis: Nokta { x: 5, y: 5, z: 5 },
};
let _ = cizgi.dizilestir(&defter);
let sonraki = kere(&defter, "alan-govdesi");
println!("Cizgi (2 nokta, 6 alan): {} govde kosumu", sonraki - onceki);
let onceki = sonraki;
let ucgen = Ucgen {
kenar1: Cizgi {
bas: Nokta { x: 0, y: 0, z: 0 },
bitis: Nokta { x: 1, y: 1, z: 1 },
},
kenar2: Cizgi {
bas: Nokta { x: 1, y: 1, z: 1 },
bitis: Nokta { x: 2, y: 2, z: 2 },
},
kenar3: Cizgi {
bas: Nokta { x: 2, y: 2, z: 2 },
bitis: Nokta { x: 0, y: 0, z: 0 },
},
};
let _ = ucgen.dizilestir(&defter);
let sonraki = kere(&defter, "alan-govdesi");
println!("Ucgen (3 cizgi, 18 alan): {} govde kosumu", sonraki - onceki);
println!("toplam alan-govdesi kosumu: {}", kere(&defter, "alan-govdesi"));
}
Nokta (3 alan): 3 govde kosumu Cizgi (2 nokta, 6 alan): 6 govde kosumu Ucgen (3 cizgi, 18 alan): 18 govde kosumu toplam alan-govdesi kosumu: 27
YN11. Nokta üç alan taşıyor ve dizilestiri üç kez alan-govdesi kaydı düşürüyor — bire
bir. Cizgi kendi alanına hiç dokunmuyor, yalnız iki Noktanın dizilestirini çağırıyor; ama
her çağrı kendi üç kaydını taşıdığı için toplam altıya çıkıyor. Ucgen aynı örüntüyü bir kat
daha derine taşıyor: üç Cizginin her biri altı kayıt bırakıyor, toplam on sekiz. Alan sayısı
ile gövde koşum sayısı arasındaki bağıntı burada bire birdir — ama bu bağıntı yalnız yaprak
düzeydeki asıl alanlar (x, y, z) için geçerli; Cizgi ve Ucgenin kendi gövdeleri hiç
alan-govdesi kaydı bırakmıyor, yalnız taşıdıkları alt yapılara devrediyor. İç içe geçme,
sayıyı toplamsal değil çarpımsal büyütüyor: Ucgenin üç kenarı, her kenarın altı kaydını
çarpıyor.
Ters Yönde Çözümleme: Bir Alanın Başarısızlığı Sonrakini Durdurur
Aynı soru ters yönden de sorulabilir: bir dizge, alan başına kaç gövde koşturarak bir yapıya
geri çevrilir? Çözümleme de elle yazılıyor — her alan alani_oku adlı ortak bir işlevden
geçiyor; bu işlev önce bir kayıt düşürüyor, sonra dizge parçasını ayrıştırmayı deniyor.
Nokta::ters_dizilestir, üç alanı sırayla okuyor ve her okuma çağrısının ardına bir soru
işareti koyuyor — Hata Yayılımının Kısa Yazımı dersinde ölçülen erken dönüş burada da geçerli:
bir alan başarısız olursa, soru işareti kalan alanların gövdesini hiç çalıştırmadan işlevden
çıkıyor.
// gozumleme.rs — ters yon: metinden yapiya, alan basina govde kosumu.
mod kere;
use kere::{kere, say, Defter};
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;
struct GozumHatasi;
struct Nokta {
x: i32,
y: i32,
z: i32,
}
fn alani_oku(defter: &Defter, ad: &str, anahtar: &str, parca: &str) -> Result<i32, GozumHatasi> {
say(defter, anahtar);
let ikili: Vec<&str> = parca.splitn(2, '=').collect();
if ikili.len() != 2 || ikili[0] != ad {
return Err(GozumHatasi);
}
ikili[1].parse::<i32>().map_err(|_| GozumHatasi)
}
impl Nokta {
fn ters_dizilestir(defter: &Defter, on_ek: &str, metin: &str) -> Result<Nokta, GozumHatasi> {
let parcalar: Vec<&str> = metin.split(';').collect();
if parcalar.len() != 3 {
return Err(GozumHatasi);
}
let x = alani_oku(defter, "x", &format!("{}-x", on_ek), parcalar[0])?;
let y = alani_oku(defter, "y", &format!("{}-y", on_ek), parcalar[1])?;
let z = alani_oku(defter, "z", &format!("{}-z", on_ek), parcalar[2])?;
Ok(Nokta { x, y, z })
}
}
fn main() {
let defter: Defter = Rc::new(RefCell::new(BTreeMap::new()));
let gecerli = Nokta::ters_dizilestir(&defter, "gecerli", "x=1;y=2;z=3");
if let Ok(n) = &gecerli {
println!("gecerli metin cozumlendi: x={} y={} z={}", n.x, n.y, n.z);
}
println!(
"gecerli-x: {} gecerli-y: {} gecerli-z: {}",
kere(&defter, "gecerli-x"),
kere(&defter, "gecerli-y"),
kere(&defter, "gecerli-z")
);
let gecersiz = Nokta::ters_dizilestir(&defter, "gecersiz", "x=1;y=degil;z=3");
println!("gecersiz metin basarili mi: {}", gecersiz.is_ok());
println!(
"gecersiz-x: {} gecersiz-y: {} gecersiz-z: {}",
kere(&defter, "gecersiz-x"),
kere(&defter, "gecersiz-y"),
kere(&defter, "gecersiz-z")
);
}
gecerli metin cozumlendi: x=1 y=2 z=3 gecerli-x: 1 gecerli-y: 1 gecerli-z: 1 gecersiz metin basarili mi: false gecersiz-x: 1 gecersiz-y: 1 gecersiz-z: 0
YN12. Geçerli dizgede (x=1;y=2;z=3) üç alan da okunuyor ve üç ayrı sayaç birer kez
artıyor — ileri yöndeki bire bir bağıntı burada da geçerli. Geçersiz dizgede (x=1;y=degil;z=3)
x alanı okunuyor ve başarılı oluyor, y alanı da okunuyor ama sayısal olarak ayrıştırılamıyor
— ikisinin de sayacı birer artıyor, çünkü ikisi de en azından denendi. z alanının sayacı
sıfırda kalıyor: soru işareti ynin başarısızlığını yakaladığı anda işlevden çıkıyor, z için
yazılan gövdeye hiç uğranmıyor. Bu, ileri yöndeki her seferinde sınıfının ters yönde koşulsuz
kalmadığını gösteriyor: bir alanın gövdesi, kendisinden önceki alanların başarısına bağlı hale
geliyor.
Sınırlayıcı Ölçüm
Alan sayısı ile gövde koşum sayısı arasındaki bire bir bağıntı, bu derste kullanılan yapıların hepsi koşulsuz alanlar taşıdığı için geçerli — her alan her zaman var, her zaman dönüştürülüyor. Yokluğun Tiple İfadesi dersinde ölçülen yokluk tipi bir alanın kendisi olsaydı, o alanın dönüşüm gövdesi artık koşulsuz çalışmazdı: bazı değerlerde koşar, bazılarında hiç koşmazdı ve alan sayısını saymak tek başına gövde koşum sayısını vermezdi. Bu ders bu durumu koşturmuyor; yalnız bağıntının hangi koşulda geçerli olduğunu, hangi koşulda bozulacağını söylüyor.
İkinci bir sınır, sayının neyi ölçmediğiyle ilgili. alan-govdesi sayacı yalnız gövdenin kaç
kez çağrıldığını sayıyor — ürettiği dizgenin ne kadar uzun olduğunu, ya da bir alanın
dönüşümünün ne kadar pahalı olduğunu ölçmüyor. Tek bir tamsayı alanı ile büyük bir koleksiyon
taşıyan bir alan, bu sayaç için aynı — ikisi de bir kez sayılıyor. Kursun başından beri
sürdürülen bu ayrım burada da geçerli: sayı yalnız kaç kez çalıştığını gösteriyor, ne kadar
sürdüğünü ya da ne ürettiğini değil.
Kapanış Tablosu
| Ders | Ölçülen gövde | Sınıfı | Sınırlayıcı ölçüm |
|---|---|---|---|
| Trait Tanımı ve Gerçekleştirimi | Varsayılan trait gövdesi (ad) |
her seferinde · hiç | Sıfır koşum, gövdenin kaynakta yok olduğu anlamına gelmez |
| Trait Sınırları | Sınırlı ve sınırsız gövdenin koşum sayısı | her seferinde | Bedel derlemede: her tip için ayrı gövde üretimi, koşumla ölçülemez |
| İlişkili Tipler | İlişkili tip / genellik parametresi çağrıları | her seferinde | Fark koşumda değil, çağıranın yazmak zorunda kaldığı bilgide |
| Nesne Güvenliği ve Dinamik Gönderim | statik-gonderim / dinamik-gonderim |
her seferinde | Aynı sayı aynı bedel değil; çağrının nasıl bulunduğu ölçülemez |
| Türetilen Trait’ler | Elle yazılan / türetilmiş eşitlik gövdesi | her seferinde (elle) · sayılamaz (türetilmiş) | Türetilmiş gövde kaynakta yazılı değil, koşum sayısı sayılamaz |
| İşleç Aşırı Yükleme | islec-govdesi (add) |
her seferinde | Çağrı yeri kaynakta görünmez, sayı ancak koşum defteriyle bilinir |
| Yokluğun Tiple İfadesi | Hazır / tembel varsayılan gövde | her seferinde · yalnız gerektiğinde · hiç | Gövde ucuzsa iki yazımın sonucu aynı, fark yalnız sayıda kalır |
| Başarısızlığın Dönüş Değeri | Başarı / başarısızlık kolu | yalnız gerektiğinde · hiç | Kapsanmış kod ile koşmuş kod ayrı olgular |
| Hata Yayılımının Kısa Yazımı | Soru işareti sonrası gövde | yalnız gerektiğinde · hiç | Erken dönüş kalan gövdeyi sessizce atlar, yan etki de gerçekleşmez |
| Özel Hata Tipleri | Hata dönüşümü gövdesi (From / map_err) |
her seferinde | Örtük dönüşüm çağıran bağlamdan bilgi alamaz, kayıp geri dönüşsüz |
| Panik ve Kurtarılamaz Hatalar | Kalan gövde (kurtarılabilir/kurtarılamaz) | her seferinde · hiç | Panik bir hata türü değil tasarım kararı; panik metni basılmadı |
| Kapanışlar | Çağrılmayan kapanış gövdesi | hiç | Kapanışın tanımlanması deftere girmeyen ayrı bir iş |
| Yineleyici Trait’i | Tüketilmeyen zincirin gövdesi | hiç | Tüketilmeyen zincir bedelsiz değil, bedel koşum sayacıyla ölçülemez |
| Yineleyici Bağdaştırıcıları | Tüketilen / erken biten zincir gövdesi | her seferinde · yalnız gerektiğinde | Sıra kaynaktan okunmaz, ancak bir kayıtla gözlemlenir |
| Dizileştirme | Alan başına dönüşüm gövdesi | her seferinde · hiç | Bağıntı yalnız her alan koşulsuzken geçerli; koşullu bir alan sınıfı değiştirir |
Özet
- Bir yapının alanlarına uygulanan dönüşüm gövdesi alan başına bir kez koşar; n alan içeren
bir yapıda bu gövde n kez çalışır —
Nokta’da üç, ikiNoktaiçerenCizgi’de altı, üçCizgiiçerenUcgen’de on sekiz kez. - İç içe geçmiş bir yapıda alan sayısı çarpımsal büyür (3, 6, 18) ve gövde koşum sayısı bu büyümeyi birebir izler.
- Bu gövde her seferinde sınıfına girer: her alan, dizileştirme her çağrıldığında kaçınılmaz olarak dönüştürülür.
- Ters yönde — metinden yapıya — bir alanın çözümlemesi başarısız olduğunda soru işareti geri kalan alanların gövdesini sessizce atlar; bu alanlar o koşumda hiç çalışmaz.
- Bir alan koşulsuz değilse (yokluk tipi taşıyorsa) bu bağıntı bozulur; alan sayısını saymak artık gövde koşum sayısını vermez.
- On beş ders boyunca ölçülen bütün gövdeler üç sınıfa (her seferinde, yalnız gerektiğinde, hiç) yerleşti; kapanış tablosu bunları tek yerde topluyor.
Kurs Kapanışı
Bu kurs on beş ders boyunca tek bir soruyu sürekli farklı düzeneklere uyguladı: kaynakta yazdığın bu gövde kaç kez koştu? Trait ve Genellikler konusu bu soruyu bir davranışın tipten ayrılmasına, bir sınırın koşuma bir şey ekleyip eklemediğine, bir sözleşmenin iki farklı yazımına, bir gönderim biçiminin derleme zamanı mı koşum zamanı mı çözüldüğüne, bir gövdenin kaynakta hiç yazılı olmadan da koşabileceğine ve bir işlecin arkasında saklı bir çağrıya sordu. Hata Yönetimi konusu aynı soruyu bir yedek değere, bir başarı/başarısızlık koluna, bir kısa yazımın arkasındaki dallanmaya, bir hata dönüşümüne ve bir kurtarılamaz duruma taşıdı. Kapanışlar ve Yineleyiciler konusu ve bu son ders, aynı soruyu bir tanımın kendisine, bir dolaşım sözleşmesine, bir zincirin ucundaki tüketiciye ve şimdi bir yapının alanlarına uyguladı. On altı gövdelik ölçüm çekirdeğinin sekizi her seferinde, üçü yalnız gerektiğinde, beşi hiç koşmadı — bu sayı kurs boyunca değişmedi, yalnız hangi düzeneğin bu sınıflara girdiği değişti.
Eşzamanlılık ve Asenkron Rust kursu bu soruyu bırakmıyor, öznesini değiştiriyor: bir gövdenin kaç kez koştuğu yerine, bir işin ilerlemek için neye ihtiyaç duyduğu sorulacak — kendi başına mı ilerliyor, bir yoklayıcı mı ilerletiyor, bir başkasının bitmesini mi bekliyor, yoksa hiç mi ilerlemiyor. Nesneye Dayalı Java kursunun kararı hangi tipin verdiği sorusunun ve Arayüzler, Hatalar ve Genellikler kursunun bağın nerede kurulduğu sorusunun yanına, bu kurs kaç kez koştu sorusunu ekledi; sıradaki kurs bu üçlüye ilerlemek için neye ihtiyaç duyulduğu sorusunu ekleyecek.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.