---
title: 'Denetim Akışı'
source: 'https://academia.sh/tr/kurslar/rust-temelleri/denetim-akisi'
course: 'Rust Temelleri'
language: tr
updated: '2026-09-13T05:09:29+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'if, match, loop, while, for biçimlerinden hangilerinin bir ifade olarak değer ürettiğini koşturarak sınıflandırır'
    - "if ve match'in bütün dallarının aynı tipi vermesi gerektiğini ve etiketli bir break'in iç içe döngüden değer taşıyabildiğini gösterir"
    - "Else'siz bir if'in de bir ifade olduğunu ve değerinin () olduğunu kanıtlar"
---

# Denetim Akışı

if, match, loop, while, for — beş denetim akışı biçiminden yalnız üçü bir değer üretebilir: if ve match birer ifadedir ve bütün dallarının aynı tipi vermesi zorunludur, loop yalnız break ile değer verir, while ve for hiçbir zaman vermez; etiketli bir break, iç içe döngülerden bir değeri doğrudan dışarıya taşıyabilir.

Önceki ders `if`/`else if`/`else` zincirini zaten bir ifade olarak kullandı, ama bu beş
denetim akışı biçiminden (`if`, `match`, `loop`, `while`, `for`) yalnız birinin durumunu
gösterdi. Bu ders beşini birden yan yana koşturuyor ve tek bir soruyu her birine soruyor:
bu biçim, kullanıldığı yerde bir değer üretiyor mu, yoksa yalnız bir iş mi yapıyor?

Bu beş biçim, çoğu dilde tek bir kategori altında toplanır — "denetim akışı yapıları" —
çünkü hepsi programın hangi satırların ne sırayla çalışacağını belirler. Rust'ta bu ortak
işlev korunuyor, ama beşi ayrıca ikiye bölünüyor: kimi biçim akışı yönlendirirken bir değer
de üretiyor, kimi biçim yalnız akışı yönlendiriyor. Bu ayrım rastgele değil — kursun baştan
beri sorduğu soruyla aynı eksende duruyor ve bu derste beş biçim üzerinden tek seferde
yanıtlanıyor.

## Beş Biçim, Üç Yanıt

```rust
// denetim_akisi.rs — bes bicimden kaci deger uretiyor
fn main() {
    let sayi = 7;

    let if_sonucu = if sayi % 2 == 0 { "cift" } else { "tek" };
    println!("if: {}", if_sonucu);

    let match_sonucu = match sayi {
        0 => "sifir",
        n if n % 2 == 0 => "cift",
        _ => "tek",
    };
    println!("match: {}", match_sonucu);

    let mut sayac = 0;
    let loop_sonucu = loop {
        sayac += 1;
        if sayac == 5 {
            break sayac * 10;
        }
    };
    println!("loop: {}", loop_sonucu);

    let mut toplam = 0;
    let while_sonucu = while toplam < 3 {
        toplam += 1;
    };
    println!("while: {:?}", while_sonucu);

    let mut liste_toplami = 0;
    let for_sonucu = for eleman in [1, 2, 3] {
        liste_toplami += eleman;
    };
    println!("for: {:?}", for_sonucu);
    println!("liste_toplami: {}", liste_toplami);
}
```

```
if: tek
match: tek
loop: 50
while: ()
for: ()
liste_toplami: 6
```

Beş biçim üç ayrı yanıt veriyor. `if` ve `match` birer değer üretiyor — hangi dal seçilirse
o dalın değerini veriyorlar. `loop` da bir değer üretiyor, ama yalnız `break`e bir değer
verildiğinde; burada `sayac` beşe ulaştığında `break sayac * 10` çalışıyor ve `loop`un
kendisi `50` değerine dönüşüyor. `while` ve `for` ise hiçbir zaman bir değer üretmiyor —
ikisi de her koşulda `()` veriyor, döngü gövdesi ne yaparsa yapsın. `for` döngüsünün
içindeki `liste_toplami` değişkeni bunu netleştiriyor: döngünün kendi değeri `()`dir, ama
gövdesinin içindeki bir yan etki (bir dış değişkeni güncellemek) döngünün asıl işini
görüyor.

Bu üç yanıt rastgele dağılmıyor; her birinin kaynağı biçimin kendi kurgusunda. `if` ve
`match` **seçicidir** — birden çok dal sunar, tam olarak birini seçer ve dilin doğal
tercihi seçilen dalın değerini bütün ifadenin değeri saymaktır. `loop` **sınırsızdır** —
kendi başına ne zaman duracağını bilmez, bu yüzden bir değeri ancak açıkça `break`e
verildiğinde üretebilir; `break` hiç çağrılmazsa `loop` da hiç bitmez ve "değeri" sorusu
gündeme bile gelmez. `while` ve `for` ise **koşulludur** — döngünün her turu bir koşula
(`while`da açık bir mantıksal ifade, `for`da bir yineleyicinin tükenip tükenmediği) bağlı
ve döngü bu koşul yanlış olduğunda kendiliğinden duruyor. Bu doğal duruşun hangi turda
gerçekleşeceği kaynaktan görünmüyor, bu yüzden dilin bu iki biçime bir değer vermesi
anlamsız olurdu — hangi durumun "sonuç" sayılacağını kaynak kendisi söylemiyor.

Bu üçlü ayrımın bir sonucu daha var: `loop`, sınırsız olduğu için, aslında `while true { }`
ile aynı akışı kurabilir — ikisi de kendiliğinden durmaz. Ama yalnız `loop` bir değer
üretebiliyor, `while true { }` üretemiyor; çünkü `while`ın kendisi, koşulu ne olursa olsun,
hiçbir zaman `break`e bir değer taşıma imkânı sunmuyor. Aynı sınırsız akış, iki farklı
biçimle yazıldığında iki farklı yeteneğe sahip oluyor.

**RD15.** `if` ve `match`in bir değer üretebilmesinin bir koşulu var: bütün dalları
**aynı tipte** bir değer vermek zorunda. Yukarıdaki `if_sonucu` örneğinde her iki dal da
`&str` veriyor; `match_sonucu`da üç dalın üçü de `&str` veriyor. Bir dal başka bir tip
verseydi (örneğin bir dal `&str`, öbürü `i32` verseydi) derleyici reddederdi — çünkü
`if_sonucu` ya da `match_sonucu`nun **tek bir** tipi olmak zorunda ve o tip hangi dalın
seçildiğine bakılmadan, derleme zamanında bilinmek zorunda.

`match_sonucu`daki ikinci dal (`n if n % 2 == 0 => "cift"`) bir **koruma koşulu (match
guard)** taşıyor: `n` deseni `sayi`nin değerini yakalıyor, `if n % 2 == 0` ise bu dalın
yalnız yakalanan değer çift olduğunda seçilmesini sağlıyor. Bu, desen eşlemenin ileride
ayrıca ele alınacak daha geniş bir örneğidir; burada yalnız bir dalın seçilip
seçilmeyeceğine ek bir koşulun karar verebildiğini görmek yeterli — sonucu, dalın hâlâ tek
bir değer (`"cift"`) üretmesi.

Bu kısıt, `match`in koruma koşulu taşıyan dalında da görülen bir başka özelliği açıklıyor:
`match`in kaç dal taşıdığı ve dalların hangi koşullarla seçildiği çalışma zamanına kadar
belli olmayabilir, ama dalların **tipi** hep derleme zamanında bellidir. Derleyici hangi
dalın koşacağını bilmeden de bütün dalların tipini denetleyebiliyor, çünkü tip denetimi
kaynağın tamamına bakıyor, yalnız çalışma zamanında seçilecek tek bir dala değil. Bu, tip
güvenliğinin **hangi dalın seçildiğinden bağımsız** olarak sağlanmasının nasıl mümkün
olduğunu gösteriyor: her dal ayrı ayrı denetleniyor, sonra hepsinin aynı tipte olduğu
doğrulanıyor — hiçbiri koşmadan önce.

## Etiketli Döngüden Değer Taşımak

`loop`un `break` ile değer üretmesi, iç içe geçmiş döngülerde bir sorun doğuruyor:
`break` en yakın çevreleyen döngüyü kırıyor, ama bazen bir değeri **daha dıştaki** bir
döngüden çıkarmak gerekiyor. Rust bunu döngü etiketleriyle çözüyor.

```rust
// etiketli_donguler.rs — ic ice donguden bir deger disariya tasinir
fn main() {
    let hedef = 6;
    let mut i = 1;
    let sonuc = 'disarisi: loop {
        let mut j = 1;
        loop {
            if j > 5 {
                break;
            }
            if i * j == hedef {
                break 'disarisi (i, j);
            }
            j += 1;
        }
        i += 1;
        if i > 5 {
            break (0, 0);
        }
    };
    println!("bulunan cift: {:?}", sonuc);
}
```

```
bulunan cift: (2, 3)
```

Burada iki `loop` iç içe. İçteki döngünün etiketi yok ve kendi `break`i yalnız kendisini
kırıyor — `j` beşi aştığında bu iç döngü sona eriyor ve dıştaki döngü `i`yi artırarak devam
ediyor. Dıştaki döngü `'disarisi` etiketini taşıyor; `break 'disarisi (i, j)` satırı, içteki
döngünün **tam ortasından**, doğrudan dıştaki döngüyü kırıyor ve `(i, j)` demedini
`sonuc`a taşıyor. `i=2, j=3` çarpımı hedefi (`6`) verdiğinde bu satır çalışıyor ve döngü
zinciri anında sona eriyor.

Bu kalıp, iki boyutlu bir alanda arama yapan her koda tanıdık gelir: bir tabloda, bir
ızgarada ya da iki değişkenli bir arama uzayında belirli bir koşulu sağlayan ilk çifti
bulmak. Etiketsiz `break` kullanılsaydı, koşul sağlandığında yalnız içteki döngü
kırılabilirdi; dıştaki döngü devam eder, `i`yi artırıp taramayı sürdürürdü — sonucu
saklamak için ayrı bir bayrak değişkeni ve dıştaki döngüde ek bir kontrol gerekirdi.
Etiketli `break`, bu ek denetimi ortadan kaldırıp arama sonucunu doğrudan döngü zincirinin
kendi değeri yapıyor.

**RD16.** Etiketli `break`, yalnız hangi döngünün kırılacağını seçmiyor, aynı zamanda
değerin **hangi döngüye** ait olduğunu da belirliyor. `sonuc`un değeri, en dıştaki
`'disarisi loop`un değeridir — içteki döngünün kendisi hiçbir zaman bir değer üretmedi,
üretemez de, çünkü içteki `break;` hiçbir değer taşımıyor. Bir demet döndürme yeteneği
yalnız etiketlenen döngüye ait; iç döngü yalnız kendi akışını kontrol ediyor, dış döngünün
sonucuna doğrudan karışamıyor — o yalnız etiketli `break` ile mümkün.

Kaynaktaki iki `break` satırı bu yüzden aynı anahtar sözcüğü taşısa da farklı işler
yapıyor. Etiketsiz `break;` en yakın çevreleyen döngüyü kırıyor — burada içteki döngüyü —
ve hiçbir değer taşımıyor, çünkü içteki döngü hiç bir sonuca bağlanmadı. Etiketli
`break 'disarisi (i, j)` ise arada kaç döngü olursa olsun doğrudan adı geçen döngüye
atlıyor ve o döngünün değerini belirliyor. Bu iki kullanım aynı derste, aynı dosyada yan
yana durabiliyor, çünkü etiket yalnız hedefi değiştiriyor; söz dizimi ve anahtar sözcük
aynı kalıyor.

Etiketleme yalnız `break` için değil, `continue` için de geçerlidir — bir sonraki tura
etiketli bir döngüden geçmek de aynı `'ad:` söz dizimini kullanır. Bu ders yalnız değer
taşıyan `break`i ölçtü, çünkü kursun ekseni değer üretimidir; `continue`ün etiketlenmesi de
aynı hedefleme mantığını izliyor, yalnız bir değer taşımıyor.

## Sınırlayıcı Ölçüm: Elsesiz `if` de Bir İfadedir

Buraya kadar görülen her `if` bir `else` dalı taşıyordu. `else` dalı olmayan bir `if` de bir
ifadedir — yalnız değeri her zaman `()`dir.

```rust
// elsesiz_if.rs — elsesiz bir if de bir ifadedir, degeri ()dir
fn main() {
    let sayi = 4;
    let sonuc = if sayi % 2 == 0 {
        println!("cift bulundu: {}", sayi);
    };
    println!("elsesiz if in degeri: {:?}", sonuc);
}
```

```
cift bulundu: 4
elsesiz if in degeri: ()
```

`sonuc` gerçekten bir bağlamaya bağlandı — bu, `if`in bir ifade olarak değerlendirildiğini
kanıtlıyor, çünkü Rust bir deyimi bir bağlamaya bağlamana izin vermez. Ama `sonuc`un değeri
`()`, çünkü koşul sağlanmadığında ne olacağı hiç yazılmadı ve Rust bu boşluğu `()` ile
dolduruyor — sanki görünmeyen bir `else { }` varmış gibi.

Bu, `if`in dallarının "aynı tipi vermesi" kuralının `else`siz durumdaki karşılığıdır: bir
`else`siz `if`in gövdesi, `sayi` gibi bir `i32` üretmeye kalksaydı (`if sayi % 2 == 0 {
sayi }`, hiç `else` yazmadan), derleyici reddederdi. Çünkü yazılmayan `else` dalı örtük
olarak `()` üretiyor sayılıyor ve gövde `i32` üretirse iki "dal" (yazılan gövde, örtük
`else`) farklı tipte olurdu — tıpkı önceki bölümdeki `if_sonucu` örneğinde iki dalın aynı
tipte olması gerektiği gibi. Bir `else`siz `if`in gövdesi bir değer üretecekse, o değer
`()`ten başka bir şey olamaz; aksi hâlde gövdenin sonuna bir noktalı virgül eklenip
değerin sessizce atılması gerekir.

Bu sınır, kaynak yazarken bir kestirme sağlıyor: bir `if` yalnız bir yan etki için
yazılıyorsa (bir yazdırma, bir güncelleme) ve karşıt durumda yapılacak hiçbir şey yoksa,
`else` dalı yazmaya gerek kalmıyor — derleyici zaten `()` bekliyor ve gövde de `()`
üretiyor. `else` yalnız iki dalın da **farklı bir değer** üretmesi gerektiğinde zorunlu
oluyor.

Bu, önceki dersteki noktalı virgül kuralıyla aynı aileden bir gözlem. Orada bir fonksiyon
gövdesinin son satırına noktalı virgül eklemek, gövdenin ürettiği değeri `()`e çeviriyordu;
burada bir `if`in `else` dalını hiç yazmamak, aynı sonuca farklı bir yoldan ulaşıyor —
yazılmayan dal, örtük olarak `()` üretiyor sayılıyor. İkisi de aynı ilkeyi taşıyor: Rust'ta
bir "eksik" değer, kaynağın hiçbir yerinde tanımsız bırakılmıyor; eksik olan yer hep `()`e
karşılık geliyor.

Beş biçimin üçe ayrılması, kaynağı yazarken de bir seçim sunuyor: bir hesaplamayı belirli
sayıda dal arasından seçen bir yapıya mı ihtiyacın var (`if`, `match`), yoksa durma koşulu
önceden bilinmeyen, açık uçlu bir tekrara mı (`loop`), yoksa sonu koşuldan önceden belli bir
tekrara mı (`while`, `for`)? Bu üç soru birbirinden bağımsızdır ve her birinin yanıtı, o
biçimin değer üretip üretmeyeceğini de beraberinde getiriyor. Bir programcı "bu döngü bana
bir sonuç verecek mi" sorusunu sormadan önce, hangi döngü biçimini seçtiğine bakması
yeterli — yanıt biçimin kendisinde saklı.

Bu ders, altı derslik bu bölümün topladığı bütün parçaları tek bir yerde birleştiriyor.
İlk ders üç sınıfı (ifade, deyim, öğe) tanımladı ve bir ölçüm çekirdeğiyle sayıya döktü;
ikinci ders bu sınıfların proje düzeyinde de geçerli olduğunu gösterdi; üçüncü ders bağlamayı
kurdu; dördüncü ders bağlanan değerlerin tiplerini kurdu; beşinci ders bir fonksiyon
gövdesinin bu üç sınıfı nasıl tek bir dönüş değerinde topladığını gösterdi. Bu ders, son
olarak, denetim akışının kendisinin — programın hangi satırın ne zaman çalışacağını
belirleyen beş biçimin — aynı üç sınıfa nasıl uyduğunu ölçtü. Kaynakta yazılan hiçbir şey bu
sınıflandırmanın dışında kalmadı: en küçük bir işleçten en büyük bir denetim yapısına kadar,
her satır ya bir değer üretiyor ya `()` üretiyor ya da yalnız bir ad bildiriyor. Bu, altı
dersin başında sorulan tek sorunun — kaynakta yazdığın bu şey bir değer mi üretiyor — neden
tek bir dersle sınırlı kalmayıp bir bölümün tamamını taşıyabildiğini de açıklıyor: soru
büyümüyor, yalnız uygulandığı yazım genişliyor.

## Özet

- Beş denetim akışı biçiminden üçü değer üretebiliyor: `if`, `match` her zaman (bir dal
  seçilerek), `loop` yalnız `break`e bir değer verildiğinde.
- `while` ve `for` hiçbir zaman değer üretmiyor; ikisi de her koşulda `()` veriyor.
- `if` ve `match`in bütün dalları aynı tipte bir değer vermek zorunda; aksi hâlde derleyici
  reddeder.
- Etiketli bir `break`, iç içe döngülerden bir değeri doğrudan en dıştaki etiketli döngüye
  taşıyabiliyor; etiketlenmemiş döngüler yalnız kendi akışlarını kontrol edebiliyor.
- `else`siz bir `if` de bir ifadedir ve değeri her zaman `()`dir; gövdesi başka bir tip
  üretmeye kalkarsa derlenmez.
- Kaynakta yazılan hiçbir şey ifade / deyim / öğe sınıflandırmasının dışında kalmıyor; bu
  ders, denetim akışının en karmaşık biçimlerinin de aynı üç yanıttan birine girdiğini
  gösterdi.

## Sonraki Adım

Bu altı derste denetim akışının değer üretip üretmediği, tek tek biçimlere bakılarak
ölçüldü. Sıradaki konu aynı soruyu **veriye** taşıyor: bir tip nasıl kuruluyor, kaç durum
taşıyor ve o durumlar nasıl ayrıştırılıyor — yapılar ve numaralandırmalarla başlayan yeni
bir bölüm bu soruları tek tek ele alacak. Şimdiye kadar görülen tipler dilin kendi
sunduğu hazır tiplerdi (tam sayı, kayan noktalı, demet); sıradaki bölümde bu tiplerden
yenilerinin nasıl **tanımlandığı** — alanların bir arada toplanması, durumların bir arada
sayılması — ele alınacak.
