Files

6.4 KiB


baslik: Hata yönetimi: sonuc ve ? bolum: Hatalar ve dosyalar ozet: Başarı ya da hata döndüren fonksiyonlar, ? ile hata iletmek ve belki

Programlar her zaman yolunda gitmez: kullanıcı yaş yerine "otuz" yazar, bir sayı sıfıra bölünür, aranan kayıt bulunamaz. KabaLang'de beklenebilir hatalar dönüş değeriyle bildirilir: fonksiyon ya başarıyı ya da hatayı döndürür ve çağıran taraf ikisini de ele almak zorundadır.

sonuc: başarı ya da hata

Dönüş türü sonuc<sayi, Hata> olan bir fonksiyon başarıda tamam(deger), başarısızlıkta hata("mesaj") döndürür.

fonksiyon bol(a: sayi, b: sayi) -> sonuc<sayi, Hata>:
    eger b == 0:
        don hata("sıfıra bölünemez")
    don tamam(a // b)

r = bol(20, 4)
eger r.tamam_mi():
    yazdir(f"Sonuç: {r.deger()}")

h = bol(5, 0)
eger h.hatali_mi():
    yazdir("Hata: " + h.hata().mesaj())
Sonuç: 5
Hata: sıfıra bölünemez
Yazım Anlamı
tamam(deger) başarı döndür
hata("mesaj") hata döndür
.tamam_mi() / .hatali_mi() hangisi olduğunu sor
.deger() başarıdaki değeri al — sonuç hatalıysa program burada durur, önce tamam_mi() ile sor
.hata().mesaj() hatanın açıklamasını al
.deger_veya(yedek) hata varsa yedek değeri ver

Yedek değerle devam etmek

Hatanın nedeni seni ilgilendirmiyorsa deger_veya() ile bir yedek değer verirsin.

fonksiyon bol(a: sayi, b: sayi) -> sonuc<sayi, Hata>:
    eger b == 0:
        don hata("sıfıra bölünemez")
    don tamam(a // b)

yazdir(bol(20, 4).deger_veya(0))
yazdir(bol(20, 0).deger_veya(0))
5
0

Girdiyi denetleyen bir fonksiyon

Kullanıcıdan gelen bir yaşı denetleyelim: boş olmasın, yalnız rakam içersin, gerçekçi olsun.

fonksiyon yas_coz(girdi: metin) -> sonuc<sayi, Hata>:
    temiz = girdi.kirp()
    eger temiz.bos_mu():
        don hata("yaş boş bırakılamaz")
    dongu harf icinde temiz:
        eger degil "0123456789".icerir(harf):
            don hata(f"'{temiz}' bir sayı değil")
    yas = sayi(temiz)
    eger yas > 130:
        don hata(f"{yas} yaş gerçekçi değil")
    don tamam(yas)

dongu g icinde ["34", " 7 ", "", "otuz", "250"]:
    r = yas_coz(g)
    eger r.tamam_mi():
        yazdir(f"✓ {r.deger()}")
    degilse:
        yazdir(f"✗ {r.hata().mesaj()}")
✓ 34
✓ 7
✗ yaş boş bırakılamaz
✗ 'otuz' bir sayı değil
✗ 250 yaş gerçekçi değil

? ile hatayı yukarı iletmek

Her çağrıdan sonra eger hatali_mi() yazmak yorucudur. Çağrının sonuna ? koyarsan şu anlama gelir: "hata varsa bu fonksiyondan da aynı hatayla hemen çık; yoksa içindeki değeri ver."

fonksiyon bol(a: sayi, b: sayi) -> sonuc<sayi, Hata>:
    eger b == 0:
        don hata("sıfıra bölünemez")
    don tamam(a // b)

fonksiyon kisi_basi(toplam: sayi, kisi: sayi, gun: sayi) -> sonuc<sayi, Hata>:
    kisi_payi = bol(toplam, kisi)?
    gunluk = bol(kisi_payi, gun)?
    don tamam(gunluk)

yazdir(kisi_basi(12000, 4, 5).deger())
yazdir(kisi_basi(12000, 0, 5).hata().mesaj())
600
sıfıra bölünemez

Dikkat: ?'yi yalnız dönüş türü kendisi de sonuc olan bir fonksiyonun içinde kullan. Hata ancak o zaman yukarı iletilebilir; programın ana akışında ya da dönüş türü olmayan bir fonksiyonda ? yerine tamam_mi() / deger_veya() kullan.

Sonucu yok saymak yasaktır

sonuc döndüren bir fonksiyonu çağırıp sonucu hiç kullanmazsan program derlenmez.

fonksiyon kaydet() -> sonuc<sayi, Hata>:
    don tamam(1)

kaydet()    # hata: bu çağrı bir 'sonuc' döndürüyor ve sonuç yok sayılıyor

Sonucu bilerek atmak istiyorsan bunu açıkça yazarsın: _ = kaydet().

belki: değer var ya da yok

Hatanın bir nedeni yoksa, yalnız "bulundu / bulunamadı" ayrımı gerekiyorsa belki<T> kullanılır: dolu(deger) ya da bos.

fonksiyon ilk_uzun_kelime(kelimeler: liste<metin>, en_az: sayi) -> belki<metin>:
    dongu k icinde kelimeler:
        eger k.uzunluk() >= en_az:
            don dolu(k)
    don bos

liste_ = ["kar", "yağmur", "fırtına"]
b = ilk_uzun_kelime(liste_, 6)
eger b.var_mi():
    yazdir(b.deger())
yazdir(ilk_uzun_kelime(liste_, 10).deger_veya("yok"))
yağmur
yok

Dikkat: .deger() yalnız değer varken okunur. bos bir belki'nin (ya da hatalı bir sonuc'un) içini .deger() ile okursan program o satırda durur ve BOS_BELKI (HATALI_SONUC) hatası verir — sessizce 0 ya da boş metin vermez. Emin değilsen önce var_mi() / tamam_mi() ile sor ya da deger_veya(yedek) kullan.

Alıştırma

`karekok_tam(n: sayi) -> sonuc<sayi, Hata>` fonksiyonunu yaz: n negatifse `"negatif sayının karekökü yok"` hatası döndürsün; değilse karesi n'yi geçmeyen en büyük tam sayıyı (`k * k <= n` olan en büyük k) döndürsün. Verilen değerler için sonucu ya da hata mesajını yazdır.
%%%
# buraya yaz

dongu n icinde [49, 50, -4]:
    r = karekok_tam(n)
    eger r.tamam_mi():
        yazdir(r.deger())
    degilse:
        yazdir(r.hata().mesaj())
%%%
fonksiyon karekok_tam(n: sayi) -> sonuc<sayi, Hata>:
    eger n < 0:
        don hata("negatif sayının karekökü yok")
    k = 0
    iken (k + 1) * (k + 1) <= n:
        k += 1
    don tamam(k)

dongu n icinde [49, 50, -4]:
    r = karekok_tam(n)
    eger r.tamam_mi():
        yazdir(r.deger())
    degilse:
        yazdir(r.hata().mesaj())
%%%
7
7
negatif sayının karekökü yok
Verilen `stok_bul` fonksiyonunu kullanan `toplam_stok(a: metin, b: metin) -> sonuc<sayi, Hata>` fonksiyonunu `?` ile yaz: iki ürünün stoklarını toplayıp döndürsün.
%%%
fonksiyon stok_bul(urun: metin) -> sonuc<sayi, Hata>:
    eger urun == "kalem":
        don tamam(40)
    eger urun == "defter":
        don tamam(25)
    don hata(f"{urun} bulunamadı")

# buraya yaz

yazdir(toplam_stok("kalem", "defter").deger())
yazdir(toplam_stok("kalem", "silgi").hata().mesaj())
%%%
fonksiyon stok_bul(urun: metin) -> sonuc<sayi, Hata>:
    eger urun == "kalem":
        don tamam(40)
    eger urun == "defter":
        don tamam(25)
    don hata(f"{urun} bulunamadı")

fonksiyon toplam_stok(a: metin, b: metin) -> sonuc<sayi, Hata>:
    x = stok_bul(a)?
    y = stok_bul(b)?
    don tamam(x + y)

yazdir(toplam_stok("kalem", "defter").deger())
yazdir(toplam_stok("kalem", "silgi").hata().mesaj())
%%%
65
silgi bulunamadı