İçeriğe geç
academia.sh

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 üç, iki Nokta içeren Cizgi’de altı, üç Cizgi içeren Ucgen’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.

Aramak için yazmaya başlayın.

↑↓ ↵ Esc gezin · aç · kapat