---
title: 'Hata Yayılımının Kısa Yazımı'
source: 'https://academia.sh/tr/kurslar/rust-soyutlama/hata-yayiliminin-kisa-yazimi'
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:
    - 'Soru işaretinden sonraki gövdenin başarılı çözümlemede bir kez, başarısızda hiç çalışmadığını koşturarak gösterir'
    - 'Kısa yazımın elle yazılan dallanmayla aynı sayıları verdiğini karşılaştırarak doğrular'
    - 'Erken dönüşün kalan gövdeyi sessizce atladığını ve atlanan adımın yan etkisi olmadığını örnekle ayırt eder'
---

# Hata Yayılımının Kısa Yazımı

Bir hatayı denetleyip erken dönmeyi tek bir işarete indirgeyen kısa yazımın, aynı işi elle yazılan bir dallanmayla birebir aynı sayıları verdiğinin — kaynağı kısalttığının, koşumu değiştirmediğinin — ölçülmesi.

Başarısızlığın Dönüş Değeri dersi, aynı işlevin art arda çağrıldığında başarı ve
başarısızlık kollarının birbirinden bağımsız çalıştığını, her ikisinin de aynı `match`
gövdesinde üç satırlık bir düzeni tekrarladığını gösterdi: değeri ayrıştır, hata varsa
bildir, yoksa devam et. Bir işlev birden çok ayrıştırma yapıyorsa bu düzen aynı biçimde art
arda tekrarlanır — her ayrıştırmadan sonra aynı iki kollu `match`. Bu ders, bu tekrarı tek
bir işarete indirgeyen kısa yazımı ölçüyor: soru işareti (`?`).

Bu konunun üçüncü dersi olarak, bu ders artık başarı ve başarısızlığın ayrı gövdeler
olduğunu varsayıyor — o ayrım önceki derste kuruldu. Burada sorulan soru bir adım öteye
geçiyor: bu iki gövdeyi ayıran `match` iskeleti, kaynakta ne kadar kısalabilir ve bu
kısalma koşumdaki sayıları değiştirir mi? Yanıt, aşağıdaki iki koşumun karşılaştırılmasıyla
ortaya çıkıyor.

Arayüzler, Hatalar ve Genellikler kursu (M09/K02) bir hatanın bir dönüş değeri olarak
taşındığını, kontrol akışının dışına çıkmadığını kurmuştu. Soru işareti de bu kararı
bozmuyor — hâlâ bir dönüş değeri üretiyor, hâlâ normal fonksiyon dönüşü kullanıyor — yalnız
o dönüşü yazmanın kaynaktaki uzunluğunu kısaltıyor. Bu ders M09/K02'nin ölçtüğü *nerede*
sorusuna dönmüyor; ölçtüğü, kısa yazımın koşumu değiştirip değiştirmediği.

Fonksiyonlar ve İfade Odaklılık dersi (M10/K01), bir işlevin gövdesi bitmeden erken
dönmenin ne zaman gerektiğini ölçmüştü: gövdenin geri kalanı hesaplanmayacaksa, açık bir
`return` bu durumu kaynakta görünür kılıyordu. Soru işareti tam olarak bu erken dönüşü
kullanıyor — yalnız `return` yazımını elle yazmak yerine, bir `Result` çağrısının hemen
ardına tek bir işaret koyarak. Bu ders o dersin kurduğu erken dönüş kavramını yeniden
kurmuyor; yalnız bu belirli kısa yazımın, elle yazılan bir erken dönüşle *aynı sayıları*
verip vermediğini ölçüyor.

## Aynı Sayılar, Daha Kısa Kaynak

Soru işareti, bir `Result` döndüren bir işlevin içinde, başka bir `Result` döndüren bir
çağrının hemen ardına yazılır. Çağrı `Ok` dönerse, içindeki değer açılır ve gövde kaldığı
yerden devam eder; `Err` dönerse, işlev o anda kendi `Err`iyle döner ve gövdenin geri kalanı
hiç çalışmaz.

Bu kısayolun bir koşulu var: soru işareti yalnız, içinde bulunduğu işlevin dönüş tipi de
bir `Result` (ya da `Option`) olduğunda yazılabilir. `main` işlevinin dönüş tipi `()` ise,
`main`in gövdesinde bir `Result` üreten bir çağrının ardına doğrudan `?` konamaz — erken
dönüşün döneceği bir `Result` yuvası yok. Bu ders bu koşulu ihlal etmiyor: `cozumle` kendi
`Result` dönüş tipini taşıyor, `?` yalnız onun gövdesinde kullanılıyor; `main` içindeki
çağrılar ise dönen `Result`ı bir değişkene bağlayıp `{:?}` ile yazdırıyor, kendisi `?`
kullanmıyor.

Aşağıdaki `cozumle` işlevinde `metin.parse()` bir `Result<i32, ParseIntError>` döndürür,
ama işlevin kendi dönüş tipi `Result<i32, SayiHatasi>`dir — iki farklı hata tipi. Soru
işareti bu farkı kendi başına çözer: `SayiHatasi` için yazılan `impl From<ParseIntError>`
gerçekleştirimi sayesinde, `parse`in ürettiği hata otomatik olarak `SayiHatasi`e
dönüştürülür. Bu dönüşümün kendisi Özel Hata Tipleri dersinin konusu; bu derste yalnız
`?`nin bu dönüşümü *kullandığı*, ama bu derste ölçülen sayıyı etkilemediği görülüyor.

```rust
// sorulu.rs — kere.rs'in cozumle kesiti: basarili columdan sonrasi bir kez, basarisizda hic kosuyor
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)
}

#[derive(Debug)]
struct SayiHatasi;

impl From<std::num::ParseIntError> for SayiHatasi {
    fn from(_: std::num::ParseIntError) -> SayiHatasi {
        SayiHatasi
    }
}

fn cozumle(defter: &Defter, metin: &str, etiket: &str) -> Result<i32, SayiHatasi> {
    let sayi: i32 = metin.parse()?;
    say(defter, etiket);
    Ok(sayi * 2)
}

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

    let basarili = cozumle(&defter, "21", "soru-sonrasi-basarili");
    let basarisiz = cozumle(&defter, "yirmibir", "soru-sonrasi-basarisiz");

    println!("basarili cagri: {:?}", basarili);
    println!("basarisiz cagri: {:?}", basarisiz);
    println!();
    for ad in ["soru-sonrasi-basarili", "soru-sonrasi-basarisiz"] {
        println!("{:<24}{} kez", ad, kere(&defter, ad));
    }
}
```

```
basarili cagri: Ok(42)
basarisiz cagri: Err(SayiHatasi)

soru-sonrasi-basarili   1 kez
soru-sonrasi-basarisiz  0 kez
```

**HT7.** `cozumle(&defter, "21", ...)` çağrısında `metin.parse()` başarıyla `21`i üretiyor;
soru işareti bu değeri açıyor, `sayi`ya bağlıyor ve gövde kaldığı yerden devam ediyor —
`say` çağrısı çalışıyor, satır `soru-sonrasi-basarili` bir kez artıyor. `cozumle(&defter,
"yirmibir", ...)` çağrısında ise `parse` bir hata üretiyor; soru işareti bu hatayı
`SayiHatasi`e çeviriyor ve işlevden hemen dönüyor. `say` çağrısına hiç sıra gelmiyor —
`soru-sonrasi-basarisiz` sıfırda kalıyor. Bu, önceki dersteki `Ok`/`Err` kollarının aynı
davranışı: biri çalışıyor, öbürü çalışmıyor. Fark, bu iki kolun artık ayrı yazılmış bir
`match` içinde değil, tek bir işaretin arkasında saklı olması.

`cozumle` işlevinin dönüş tipine bakıldığında, gövdesinde yalnız bir satır (`let sayi: i32
= metin.parse()?;`) `Result` ile ilgili görünüyor; geri kalan iki satır (`say` çağrısı ve
`Ok(sayi * 2)`) sıradan kod gibi okunuyor. Bu, soru işaretinin kaynakta bıraktığı izin ne
kadar küçük olduğunu gösteriyor — bir işlev, kaç ayrı ayrıştırma yapıyorsa yapsın, her
ayrıştırmanın ardına tek bir karakter ekleyerek hata denetimini tamamlıyor. `etiket`
parametresinin `say`e geçirilen adı taşıması, bu derste iki farklı çağrıyı (başarılı ve
başarısız) aynı işlevin üzerinden, ama ayrı sayaç anahtarlarıyla izlemeyi sağlıyor; gerçek
bir kullanımda bu parametre bulunmaz, yalnız ölçüm amacıyla eklendi.

Aynı işlev elle yazılan bir dallanmayla da kurulabilir. Aşağıdaki koşum, soru işaretini
`match` ve erken `return` ile değiştiriyor ve aynı iki girdiyle çağrılıyor.

```rust
// elle_dallanma.rs — ayni is elle dallanmayla yazilinca da ayni sayilari veriyor
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)
}

#[derive(Debug)]
struct SayiHatasi;

fn cozumle_elle(defter: &Defter, metin: &str, etiket: &str) -> Result<i32, SayiHatasi> {
    let ayristirma = metin.parse::<i32>();
    let sayi = match ayristirma {
        Ok(deger) => deger,
        Err(_) => return Err(SayiHatasi),
    };
    say(defter, etiket);
    Ok(sayi * 2)
}

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

    let basarili = cozumle_elle(&defter, "21", "soru-sonrasi-basarili");
    let basarisiz = cozumle_elle(&defter, "yirmibir", "soru-sonrasi-basarisiz");

    println!("basarili cagri: {:?}", basarili);
    println!("basarisiz cagri: {:?}", basarisiz);
    println!();
    for ad in ["soru-sonrasi-basarili", "soru-sonrasi-basarisiz"] {
        println!("{:<24}{} kez", ad, kere(&defter, ad));
    }
}
```

```
basarili cagri: Ok(42)
basarisiz cagri: Err(SayiHatasi)

soru-sonrasi-basarili   1 kez
soru-sonrasi-basarisiz  0 kez
```

**HT8.** İki koşum birebir aynı sayıları veriyor: `soru-sonrasi-basarili` bir, `soru-sonrasi-basarisiz`
sıfır. Kaynak farklı — ilkinde tek satır (`metin.parse()?`), ikincisinde beş satırlık bir
`match` — ama koşum aynı. Soru işareti yeni bir davranış eklemiyor; elle yazılan `match` ve
erken `return`ün derleyicinin ürettiği koduyla aynı işi, daha az yazarak yapıyor. Bu, kısa
yazımın *koşumu* değil *kaynağı* kısalttığının doğrudan kanıtı: iki program farklı uzunlukta
kaynağa sahip, ama aynı ikili davranışı üretiyor.

`cozumle_elle` işlevindeki `match`, önceki dersteki `match`ten bir farkla ayrılıyor: `Err`
kolu bir değer üretip gövdenin geri kalanına devretmiyor, doğrudan `return Err(SayiHatasi)`
ile işlevden çıkıyor. Bu, Denetim Akışı dersinde (M10/K01) kurulan `match`in bir ifade
olması ilkesiyle çelişmiyor — `return` bir ifade değil bir deyim ve bir `match` kolunun
içinde bir deyim yazılabilir; o kolun ürettiği "değer" gövdenin geri kalanına hiç ulaşmıyor,
çünkü işlevin kendisinden çıkılıyor. `Ok` kolu ise sıradan bir değer (`deger`) üretiyor ve
bu değer `sayi`ya bağlanıyor, gövde oradan devam ediyor. İki kolun farklı doğası —
biri işlevden çıkıyor, öbürü bir değer veriyor — soru işaretinin arkasında da aynen
duruyor, yalnız görünmez.

Kaynaktaki kısalmanın gerçek bedeli, bir işlev birden çok ayrıştırma yaptığında görülür.
Üç ayrı alanı sırayla ayrıştıran bir işlev, elle yazılan dallanmayla üç kez tekrarlanan
beş satırlık bir `match` (toplam on beş satır) gerektirirdi; aynı işlev soru işaretiyle üç
satıra iner — her alanın ardına tek bir işaret. Bu derste ölçülen iki koşum (bir satırlık
kısa yazım, beş satırlık elle yazım) bu farkın en küçük örneği; alan sayısı arttıkça
kaynaktaki fark da büyür, ama her iki yazımın da ürettiği `soru-sonrasi-basarili` /
`soru-sonrasi-basarisiz` çifti aynı kalır. Kısa yazımın büyümesi doğrusal değil — kaynak
satır sayısı azalırken, koşumun kendisi hiç değişmez.

Soru işareti `Option` üzerinde de aynı biçimde çalışır: içinde bulunduğu işlev `Option`
dönüyorsa, `Some` içindeki değeri açar, `None` durumunda işlevden hemen `None` döndürür. Bu
ders bu ikinci kullanımı koşturmuyor — Yokluğun Tiple İfadesi dersinde ölçülen `Option`
yöntemleri bir değer üretme (`unwrap_or`, `unwrap_or_else`) üzerine kuruluydu, burada
ölçülen ise erken dönüş. İki kullanım da aynı işareti taşısa da, biri bir değer üretir
(`unwrap_or_else`in yaptığı gibi), öbürü işlevden çıkar; bu derste ölçülen yalnız
`Result` üzerindeki, işlevden çıkan biçimi.

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

Yukarıdaki koşumda `soru-sonrasi-basarili` ve `soru-sonrasi-basarisiz` her zaman birlikte
hareket ediyor: biri bir olduğunda öbürü sıfır, biri sıfır olduğunda öbürü bir. Bu, tek bir
gözlemin değil, aynı satırın iki farklı çağrıdaki durumunun sonucu — ikisi de aslında aynı
`say(defter, etiket)` çağrısını temsil ediyor, yalnız `etiket` argümanı çağırana göre
değişiyor.

**HT9.** Erken dönüş, kendisinden sonraki gövdeyi sessizce atlıyor — ne bir uyarı yazdırıyor
ne bir işaret bırakıyor. `"yirmibir"` girdisiyle yapılan çağrıda `say` çağrısı hiç
çalışmadığı için sayaç defterine hiçbir kayıt düşmüyor; bu, "adım atlandı" diye bir iz
bırakmıyor, yalnız beklenen kaydın *yokluğuyla* görünüyor. Atlanan adımın kendisi bir yan
etki üretmiş olsaydı — bir dosyaya yazma, bir sayacı artırma, bir günlük satırı basma — o
yan etki de gerçekleşmezdi. Bu ders bunu tam olarak `say` çağrısının kendisiyle gösteriyor:
`say`, atlanan adımın *tek* yan etkisi ve o yan etki gerçekleşmediği için sayı sıfırda
kalıyor.

Bu, önceki dersteki `Err` kolunun kaynakta yazılı ama koşmamış olmasından farklı bir
durum. Orada iki kol da aynı `match`in içinde açıkça duruyordu, ikisi de görünürdü. Burada
"atlanan gövde" ayrı bir kol olarak yazılmıyor — soru işaretinden sonraki her satır, hata
durumunda örtük olarak atlanıyor. Kaynağı okuyan biri, `?`den sonraki satırların hangi
koşulda çalışacağını görebilir, ama derleyicinin bunun için ayrı bir kol ürettiğini
kaynakta görmez; bu kol yalnız koşumda, sayaçla ölçüldüğünde ortaya çıkıyor.

Bu sessizlik bir tasarım kararının sonucu, bir kusur değil. Soru işareti bir uyarı
yazdırmıyor, çünkü hatanın kendisi zaten dönüş değeri olarak taşınıyor — çağıran taraf bu
değeri denetlediği sürece, "neden atlandığı" bilgisi kayıp değil, yalnız gövdenin geri
kalanında değil, dönüş değerinde duruyor. Bu ders bu bilgiyi izlemiyor; yalnız gövdenin geri
kalanının çalışıp çalışmadığını sayıyor. Bir işlevin `cozumle`yi çağıran tarafı, dönen
`Result`ı denetlemezse, hem bu bilgiyi hem de neyin atlandığını görme fırsatını kaybeder —
ama bu, soru işaretinin değil, çağıran tarafın denetlememe kararının sonucu.

Aynı sessiz atlama, işlev sınırlarını art arda geçen bir soru işareti zincirinde de aynı
biçimde tekrarlanır. Bir işlev kendi içinde soru işaretiyle başka bir işlevi çağırıyorsa
ve o işlev de kendi içinde bir üçüncü işlevi soru işaretiyle çağırıyorsa, en alttaki
başarısızlık üç ayrı gövdeyi de sessizce atlayarak en üste kadar yükselir — hiçbiri bir iz
bırakmadan. Bu ders bu çok katmanlı zinciri koşturmuyor; yalnız tek bir sınırda, atlamanın
kendisinin sessiz olduğunu gösteriyor.

Bu üç katmanlı zinciri düşünmek sınırı daha da netleştiriyor. En alttaki işlev bir
ayrıştırma yapıyor ve başarısız oluyor diyelim; onu çağıran orta katman kendi gövdesinde
üç satır daha çalıştıracaktı, ama hiç çalıştırmıyor; en üstteki çağıran ise beş satır daha
çalıştıracaktı, o da çalıştırmıyor. Toplamda sekiz satırlık gövde, tek bir başarısızlık
yüzünden sessizce atlanmış oluyor — ama kaynakta bu sekiz satırın "atlanabilir" olduğunu
işaretleyen hiçbir yorum, hiçbir özel söz dizimi yok. Yalnız her üç katmanın da kendi
dönüş tipinin `Result` olması ve her katmanın çağrısının ardında bir soru işareti
bulunması, bu sessiz atlamanın mümkün olduğunu gösteriyor.

Bu konunun ilk iki dersinde ölçülen ayrım burada da geçerliliğini koruyor: `Option`da hazır
ve tembel gövdeler arasındaki fark, `Result`da başarı ve başarısızlık kolları arasındaki
fark, burada da aynı biçimde duruyor — yalnız artık `match` kolları elle yazılmıyor, tek
bir işaretin ardında saklanıyor. Kısa yazım, ölçülen üç sınıfın (her seferinde, yalnız
gerektiğinde, hiç) hiçbirini ortadan kaldırmıyor; yalnız o sınıfları taşıyan kaynağı
küçültüyor.

## Özet

- Soru işareti, bir `Result` çağrısının ardından yazılan erken dönüşü tek bir işarete
  indirger; `Ok` dönerse değeri açar ve gövde devam eder, `Err` dönerse işlev hemen döner.
- Soru işaretinden sonraki gövde, çağrı başarılı olduğunda **yalnız gerektiğinde** çalışır
  — çağrı başarısız olduğunda **hiç** çalışmaz.
- Aynı işlev elle yazılan bir `match` ve erken `return` ile kurulduğunda **aynı sayıları**
  verir: kısa yazım koşumu değil, kaynağı kısaltır — bu fark, bir işlev birden çok
  ayrıştırma yaptıkça büyür.
- Erken dönüş kalan gövdeyi sessizce atlar; atlanan adımın hiçbir yan etkisi de
  gerçekleşmez — ne bir uyarı, ne bir kısmi kayıt.
- Atlanan gövde kaynakta ayrı bir kol olarak görünmez; yalnız sayaçla ölçüldüğünde,
  eksik kalan kayıtla fark edilir.
- Soru işareti farklı hata tiplerini `From` ile otomatik dönüştürür; bu dönüşümün kim
  tarafından çağrıldığı sıradaki dersin konusudur.

## Sonraki Adım

Yukarıdaki `SayiHatasi`, `std::num::ParseIntError`i kendi tipine dönüştüren bir `From`
gerçekleştirimi taşıyordu — soru işaretinin bu dönüşümü nasıl çağırdığı bu derste
gösterilmedi, yalnız kullanıldı. `cozumle` işlevinin gövdesinde bu dönüşümü çağıran açık
bir satır yok; `metin.parse()?` yazımının kendisi hem hatayı denetliyor hem de gerekirse
dönüştürüyor. Özel Hata Tipleri dersi bu dönüşümü kimin çağırdığını ölçüyor: kısa yazım bu
çağrıyı çağıran taraf hiçbir şey yazmadan mı yapıyor, yoksa elle yazılan bir dönüşüm mü
gerekiyor — ve iki yaklaşım aynı bilgiyi taşıyabiliyor mu, yoksa örtük dönüşüm bir şeyi
kaybediyor mu?
