---
title: 'Panik ve Kurtarılamaz Hatalar'
source: 'https://academia.sh/tr/kurslar/rust-soyutlama/panik-ve-kurtarilamaz-hatalar'
course: "Trait'ler, Genellikler ve Hata Yönetimi"
language: tr
updated: '2026-10-21T05:03:45+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Kurtarılabilir ve kurtarılamaz iki tasarımı koşturarak kalan gövdenin kaç kez çalıştığını karşılaştırır'
    - 'Panik durumunun gerçekten tetiklenmesi gerekmeden, aynı ayrımın nasıl modellenebileceğini açıklar'
    - 'Panik seçiminin bir hata türü değil bir tasarım kararı olduğunu örnekle ayırt eder'
---

# Panik ve Kurtarılamaz Hatalar

Bir başarısızlığın çağırana hiçbir seçim bırakmadan kalan gövdeyi durdurduğu bir tasarımın, aynı başarısızlığın bir dönüş değeriyle karşılandığı tasarımla yan yana modellenmesi ve iki tasarımın kalan gövde için verdiği sayıların karşılaştırılması.

Go Temelleri kursu (M09/K01), bir panik durumunu gerçekten tetikleyip bir kurtarma
çağrısıyla yakalayarak `panik=true` / `panik=false` biçiminde bir sonuç bastı — panikte
yığıt izi, kurtarmanın kendisinde ise yalnız bir bayrak görünür kılındı. O kurs bu yakalama
düzeneğini kullanabildi, çünkü panik orada tek bir çağrının sınırında, denetimli biçimde
tetiklendi. Bu ders aynı ayrımı hiç tetiklemeden ölçüyor: gerçek bir panik durumu ne
kurulur ne de bir kurtarma çağrısıyla yakalanır. Panik metni ortama bağlı bir veridir —
dosya adı, satır numarası, çağrı yığıtının biçimi çalıştırılan makineye göre değişir — ve
bu ders böyle bir metin basmaz.

Bunun yerine ayrım **modellenir**: aynı başarısızlık bir kez `Result` ile karşılanan bir
tasarımda, bir kez de "buradan sonrası koşmaz" biçiminde yazılan bir tasarımda kuruluyor
ve iki tasarımın kalan gövde için verdiği sayılar karşılaştırılıyor. Özel Hata Tipleri
dersi, bir başarısızlığın bir değer olarak taşınabileceğini ve çağıranın bu değerle ne
yapacağına kendisi karar verdiğini gösterdi. Bu ders o kararın *reddedildiği* bir tasarımı
ölçüyor: çağırana hiçbir seçim bırakmayan bir başarısızlık.

Bu konunun önceki dört dersinde ölçülen her düzenek — yokluk, başarısızlık kolları, kısa
yazım, dönüşüm — bir ortak varsayımı paylaşıyordu: başarısızlık bir *değerdi* ve program
o değerle birlikte çalışmaya devam ediyordu. Bu son ders o varsayımın sınırını arıyor: her
başarısızlık bu biçimde ele alınabilir mi, yoksa bazı durumlar için "devam et" seçeneğinin
kendisi anlamsız mı? Kurtarılamaz bir durum, tanımı gereği, `Result` döndürüp çağırana
bırakılamayacak kadar temel bir varsayımın çöktüğü durumdur — ve bu ders bu iki türü
birbirinden ayırmak yerine, ikisinin *kalan gövde* üzerindeki etkisini sayıyor.

## İki Tasarım, Aynı Koşul

Ders başlığındaki iki sözcük — panik ve kurtarılamaz hata — aynı fikrin iki adı. "Panik",
Rust'ın çalışma zamanının bu durumu adlandırma biçimi; "kurtarılamaz hata", aynı durumun
kavramsal adı, yalnız Rust'a özgü değil. Bu ders ikisini de aynı ölçünün altında ele
alıyor: bir başarısızlığın, çağırana devam etme seçeneği bırakmadan, kalan işi durdurması.

Aşağıdaki iki koşum aynı geçersiz girdiyi (`-5`) iki farklı tasarımla ele alıyor. İlkinde
başarısızlık bir `Result` ile karşılanıyor ve çağıran, hatayı gördükten sonra da kalan
işini sürdürüyor.

```rust
// kurtarilabilir.rs — hata bir deger, cagiran devam etmeyi seciyor
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;

type Defter = Rc<RefCell<BTreeMap<String, u32>>>;

fn say(defter: &Defter, ad: &str) {
    *defter.borrow_mut().entry(ad.to_string()).or_insert(0) += 1;
}
fn kere(defter: &Defter, ad: &str) -> u32 {
    *defter.borrow().get(ad).unwrap_or(&0)
}

fn dogrula(giris: i32) -> Result<i32, ()> {
    if giris < 0 {
        return Err(());
    }
    Ok(giris)
}

fn kalan_is(defter: &Defter) {
    say(defter, "kurtarilabilir-devam");
}

fn main() {
    let defter: Defter = Rc::new(RefCell::new(BTreeMap::new()));

    match dogrula(-5) {
        Ok(deger) => println!("gecerli deger: {}", deger),
        Err(()) => println!("gecersiz giris karsilandi, program suruyor"),
    }
    kalan_is(&defter);

    println!();
    println!("kurtarilabilir-devam: {} kez", kere(&defter, "kurtarilabilir-devam"));
}
```

```
gecersiz giris karsilandi, program suruyor

kurtarilabilir-devam: 1 kez
```

**HT13.** `dogrula(-5)` bir `Err` döndürüyor, ama bu dönüş programı durdurmuyor: `match`
`Err` kolunu işletiyor, sonra akış olağan biçimde `kalan_is`e ulaşıyor ve onu çalıştırıyor.
`kurtarilabilir-devam` bire çıkıyor. Çağıranın elinde bir seçenek vardı — hatayı görüp
devam etmek — ve bu seçeneği kullandı.

Bu tasarımda `dogrula` başarısızlığını, tam olarak bu konunun önceki dört dersinde ölçülen
düzenekle bildiriyor: `Result<i32, ()>` dönüyor, `Err` kolu bir değer taşımıyor (`()`),
ama varlığı yeterli. `main`in gövdesi bu değeri `match`le karşılıyor ve iki kolda da
program aynı yere, `kalan_is`e ulaşıyor. `kalan_is`in çağrılması `match`in bir sonucu değil
— `match` bittikten *sonra*, sıradan bir sonraki satır olarak yazılmış. Bu, önceki
derslerde görülen kalıptan bir fark: orada kollar birbirinden bağımsız işler yapıyordu, burada
her iki kol da aynı sonraki adıma çıkıyor, yalnız farklı bir mesaj yazdırarak.

İkinci tasarım aynı koşulu, çağırana bu seçeneği hiç sunmadan ele alıyor.

```rust
// kurtarilamaz.rs — kosul saglanmayinca kalan govde tasarim geregi hic cagrilmiyor
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::rc::Rc;

type Defter = Rc<RefCell<BTreeMap<String, u32>>>;

fn say(defter: &Defter, ad: &str) {
    *defter.borrow_mut().entry(ad.to_string()).or_insert(0) += 1;
}
fn kere(defter: &Defter, ad: &str) -> u32 {
    *defter.borrow().get(ad).unwrap_or(&0)
}

fn devam_isi(defter: &Defter) {
    say(defter, "kurtarilamaz-devam");
}

fn main() {
    let defter: Defter = Rc::new(RefCell::new(BTreeMap::new()));
    let giris = -5;

    if giris >= 0 {
        println!("gecerli deger: {}", giris);
        devam_isi(&defter);
    } else {
        println!("kurtarilamaz kosul: kalan govde tasarim geregi hic cagrilmiyor");
    }

    println!("kurtarilamaz-devam: {} kez", kere(&defter, "kurtarilamaz-devam"));
}
```

```
kurtarilamaz kosul: kalan govde tasarim geregi hic cagrilmiyor
kurtarilamaz-devam: 0 kez
```

**HT14.** Aynı koşul (`giris < 0`), bu kez `devam_isi`nin hiç çağrılmamasıyla sonuçlanıyor.
`kurtarilamaz-devam` sıfırda kalıyor — kaynakta yazılı, ama bu koşumda **hiç** çalışmıyor.
İki koşum yan yana konduğunda fark netleşiyor: aynı geçersiz girdi, bir tasarımda kalan
işin çalışmasına, öbüründe hiç çalışmamasına yol açıyor. Sayı, tasarımın kendisinden
kaynaklanıyor — girdinin "ne kadar geçersiz" olduğundan değil.

Bu ikinci tasarımda hiçbir `Result` yok — `main`in kendisi `if`/`else` ile karar veriyor
ve `devam_isi`yi yalnız geçerli dalda çağırıyor. `else` kolunun kendisi bir mesaj
yazdırıyor, ama bu mesaj bir hata *değeri* değil, yalnız bir bilgi notu; programın kendisi
bu mesajdan sonra normal biçimde sona eriyor. Bu ders bu ikinci tasarımı gerçek bir
kurtarılamaz durumun *modeli* olarak sunuyor — gerçek bir kurtarılamaz durum tipik olarak
programı `main`in bile bitmesini beklemeden durdurur; burada `main` olağan biçimde
tamamlanıyor, yalnız `devam_isi` çağrısı atlanmış oluyor. Model, "kalan işin çalışmaması"
sonucunu taşıyor; programın kendisinin ne zaman ve nasıl sonlandığını taşımıyor.

Bu iki program gerçek bir panik durumunu göstermiyor; ikisi de olağan `if`/`match`
dallanmasıyla yazıldı ve ikisi de normal biçimde sonlanıyor. Model, panik durumunun
*gerçek düzeneğini* (çağrı yığıtının geri sarılması) değil, panik durumunun *gözlenebilir
sonucunu* (kalan gövdenin hiç çalışmaması) taşıyor. Gerçek bir panik, bu "hiç çalışmama"
durumunu tek bir çağrıda, ara katmanlardaki her işlevi tek tek durdurmadan, otomatik
olarak üretir — bu ders bu otomasyonu kurmuyor, yalnız sonucunu iki elle yazılmış tasarımla
karşılaştırıyor.

Bu modellemenin neden gerekli olduğu, ortama bağlı veri yasağından geliyor. Gerçek bir
panik durumu tetiklendiğinde, çalışma zamanı bir metin üretir; bu metin hangi dosyada,
hangi satırda durduğunu ve çağrı yığıtının o andaki biçimini içerir. Bu bilgilerin hepsi
derleme ortamına, dosya yoluna ve hatta derleyicinin sürümüne bağlıdır — aynı kaynak kodu
farklı bir makinede derlenip çalıştırıldığında aynı metni üretmez. Bu kurs boyunca
korunan kural (gerçek yol, gerçek bellek adresi, sürüme bağlı çıktı basılmaz) burada da
geçerli; bu yüzden panik durumu gerçekten tetiklenmiyor, yerine yalnız *sayılabilir* olan
kısmı — kalan gövdenin çalışıp çalışmadığı — modelleniyor.

Bu modelleme, önceki dört derste ölçülen "derlenmeyen kaynak kod bloğuna konmaz" kuralıyla
aynı aileden. Orada derleyicinin reddi düzyazıda tarif ediliyor, kod bloğuna konmuyordu;
burada panik durumunun kendisi hiç kurulmuyor, yerine sonucu modelleniyor. İkisinde de
ortak olan, ortama bağlı bir çıktının yerine, kaynaktan okunabilen bir sayının konması.

## Sınırlayıcı Ölçüm

Yukarıdaki iki tasarım arasındaki fark, hangisinin "doğru" olduğunu söylemiyor. Panik bir
hata türü değil, bir tasarım kararıdır — aynı başarısızlık her iki biçimde de yazılabilir
ve seçim çağırana ne bırakılacağına bağlıdır.

**HT15.** Kurtarılabilir tasarım, çağırana bir seçenek bırakıyor: hatayı görmezden gelmek,
bir yedek kullanmak, ya da kendi hatasını üretmek. Kurtarılamaz olarak modellenen tasarım
ise bu seçeneği baştan kapatıyor — kalan iş, koşul sağlanmadıkça tasarım gereği hiç
çalışmıyor ve bunu değiştirmek çağıranın elinde değil. Gerçek bir panik bu ikinci
tasarımı bir adım öteye taşır: durdurma yalnız bir işlevin gövdesinde değil, o işlevi
çağıran her katmanda, hiçbir açık kod yazılmadan gerçekleşir. Bu ders bu çok katmanlı
durdurmayı koşturmuyor; yalnız tek bir katmanda, "hiç çalışmama" sonucunun nasıl
modellenebileceğini gösteriyor.

Bu fark, Hata Yayılımının Kısa Yazımı dersinde ölçülen sessiz atlamayla karşılaştırılabilir,
ama aynı şey değil. Orada erken dönüş bir `Result` üretiyordu; kalan gövde çalışmıyordu,
ama işlev normal biçimde dönüyordu ve çağıran bu dönüşü bir `match` ile karşılayabiliyordu.
Kurtarılamaz olarak modellenen bu tasarımda da işlev normal biçimde dönüyor — model
gerçek bir panik değil — ama gerçek bir panik bu noktada farklılaşır: normal bir dönüş
üretmez, çağıranın `match`le karşılayabileceği bir değer bırakmaz. Bu, kurtarılabilir ve
kurtarılamaz arasındaki asıl çizgi: biri bir değer bırakıyor, öbürü hiçbir değer
bırakmadan akışı kesiyor.

Kurtarılamaz olarak modellenen tasarımda `devam_isi` tek bir gövde olarak yazıldı, ama
gerçek bir programda kalan iş birden çok adımdan oluşabilir — bir kayıt açma, bir toplam
hesaplama, bir sonucu yazdırma. Bu ders bu adımları tek bir işlevde topladı, ama Hata
Yayılımının Kısa Yazımı dersinde görülen çok adımlı atlama burada da geçerli: `giris >= 0`
koşulu sağlanmadığında, `devam_isi`nin *içindeki* bütün adımlar da birlikte atlanır, tek
tek değil. Kalan işin kaç ayrı adımdan oluştuğu önemli değil — koşul sağlanmadığı sürece
hiçbiri çalışmıyor, hepsi birlikte "hiç" sınıfına giriyor.

Bir tasarımcının bu iki yol arasında seçim yapması gereken an, genellikle "bu durum
gerçekten oluşabilir mi, oluşursa programın geri kalanı güvenilir kalır mı" sorusuna
verilen yanıtla belirleniyor. Bir kullanıcı girdisinin geçersiz olması beklenir bir
durumdur — kurtarılabilir tasarım burada doğal bir seçimdir, çünkü çağıran bu durumu
önceden tahmin edebilir ve bir yanıtı hazır tutabilir. Buna karşılık, bir programın kendi
iç tutarlılığını bozan bir durum — örneğin bir dizinin beklenenden az eleman taşıması, bir
kurulumun eksik kalması — genellikle kurtarılamaz olarak ele alınır, çünkü bu durumda
geri kalan kodun hangi varsayımlarla yazıldığı artık geçerli değildir ve devam etmek yeni,
öngörülemeyen hatalara yol açabilir.

Bu iki uç arasında kesin bir sınır çizmek bu dersin işi değil — sınır, programın kendi
alanına ve tasarımcının kararına bağlı. Bu ders yalnız bu kararın *sonucunu* sayılabilir
kılıyor: hangi tasarım seçilirse seçilsin, kalan gövdenin çalışıp çalışmadığı, kaynağı
okuyarak değil, koşumu ölçerek doğrulanabilir. `kurtarilabilir-devam` ile
`kurtarilamaz-devam` arasındaki `1`/`0` farkı, bu konunun başından beri sürdürülen ölçünün
son örneği: kaynakta yazılan bir gövde, koşumda kaç kez çalışıyor.

Bir tasarımın kurtarılabilir mi kurtarılamaz mı olacağı, başarısızlığın *doğasından*
otomatik olarak çıkmaz — bu bir karardır. Aynı geçersiz girdi, bir programda "hatayı
günlüğe yaz, varsayılan değerle devam et" biçiminde ele alınabilir; başka bir programda,
aynı girdi "bu durum asla oluşmamalıydı, devam etmenin bir anlamı yok" biçiminde ele
alınabilir. Rust'ın kendisi bu kararı dayatmaz; `Result` de olağan işlev dönüşü de aynı
dilin parçasıdır, tercih kaynak kodu yazan tarafa aittir.

Yukarıdaki `dogrula` işlevinin `-5` girdisi, aslında iki tasarımda da "aynı" başarısızlığı
temsil ediyor — ikisinde de kaynak, negatif bir sayının geçersiz sayıldığını söylüyor. Fark
başarısızlığın *tespitinde* değil, tespit edildikten *sonra ne olacağında*. Bu, bu konunun
başından beri süren eksenle aynı yerde duruyor: kaynakta yazılan bir gövdenin koşumda kaç
kez çalıştığı. Yalnız bu kez ölçülen gövde bir yedek değer ya da bir dönüşüm değil, bir
işlevin normal akışının *geri kalanı* — ve bu geri kalanın çalışıp çalışmadığı, doğrudan
tasarımın kendisinden okunuyor.

## Özet

- Aynı başarısızlık iki tasarımla yazılabilir: kurtarılabilir tasarımda çağıran kalan
  işi kendi seçimiyle sürdürür, kurtarılamaz olarak modellenen tasarımda kalan gövde
  **hiç** çalışmaz.
- Gerçek bir panik durumu bu derste hiç tetiklenmedi; ayrım, panik metni basılmadan,
  olağan dallanmayla modellendi — çünkü panik metni dosya, satır ve çağrı yığıtı gibi
  ortama bağlı veri taşır.
- Kurtarılabilir tasarımda kalan iş çalıştı (`kurtarilabilir-devam: 1`), kurtarılamaz
  olarak modellenen tasarımda çalışmadı (`kurtarilamaz-devam: 0`) — aynı koşul, farklı
  sayı.
- Panik bir hata türü değil bir tasarım kararıdır; seçim, çağırana ne bırakılacağına
  bağlıdır — bir durumun beklenir mi yoksa programın iç tutarlılığını mı bozduğuna göre.
- Gerçek bir panik, "hiç çalışmama" sonucunu tek bir çağrıda, ara katmanları tek tek
  durdurmadan üretir; bu ders bu otomasyonu değil, yalnız gözlenebilir sonucunu ölçtü.
- Kurtarılabilir tasarımda çağıran bir değerle karşılaşır ve karar verir; kurtarılamaz
  tasarımda hiçbir değer bırakılmaz, akış doğrudan kesilir.

## Sonraki Adım

Bu konunun beş dersi boyunca ölçülen gövdeler hep bir işlevin kendi gövdesinin içindeydi —
bir işlev çağrıldığında ne kadarının çalıştığı: bir yedek değer, bir kol, bir dönüşüm, bir
kalan gövde. Beş ders de aynı üç sınıfa (her seferinde, yalnız gerektiğinde, hiç)
yerleşti, yalnız hangi düzeneğin bu sınıflara girdiği değişti. Kapanışlar dersi aynı soruyu,
bir gövdenin *ne zaman* çağrıldığına taşıyor: bir kapanış tanımlandığı anda mı çalışır,
yoksa yalnız biri onu çağırdığında mı? Bu konuda ölçülen "kaç kez koştu" sorusu orada da
sürüyor, ama artık bir başarısızlık değil, bir tanımın kendisi ölçünün konusu.
