---
title: 'Denetim Akışı'
source: 'https://academia.sh/tr/kurslar/go-temelleri/denetim-akisi'
course: 'Go Temelleri'
language: tr
updated: '2026-08-23T14:25:00+00:00'
license: 'CC BY-SA 4.0'
---

# Denetim Akışı

Beş biçim aynı soruyla ölçülüyor — koşulsuz for, tek koşullu for, ifadesiz switch, else'siz erken dönüş, kendiliğinden düşmeyen switch dalları — ve beşi de yazılmayan parçayı tanımlı bir karşılıkla dolduruyor. Sınırlayıcı ölçüm: yazılmayan break gerekmiyor, ama düşmeyi isteyen kod fazladan bir sözcük (fallthrough) yazmak zorunda.

Önceki ders on beş yazılmamışlığı ölçtü ama hiçbiri bir denetim yapısının **içinde**
değildi — hepsi bir değişkenin, bir dönüşün ya da bir argümanın yokluğuyla ilgiliydi. Bu ders
aynı soruyu denetim akışına taşıyor: `for` neden bazen koşulsuz yazılabiliyor, `switch` neden
bazen ifadesiz yazılabiliyor, ve bir dalın sonunda yazılmayan `break` neyin yerini tutuyor?

Programlama Temelleri kursu (M01/K02) koşullu dallanmayı ve döngü denetimini Python'la kurdu;
orada döngü ve dallanma için ayrı anahtar sözcükler vardı (`while`, `for`, `if`/`elif`/`else`)
ve her birinin kendi sözdizimi sabitti. **Bu kavramlar burada tekrar kurulmaz** — farkı tek
cümleyle yazmak yeter: Go, döngü için **tek** bir anahtar sözcük (`for`) kullanıyor ve bu
sözcüğün hangi klasik döngü biçimine karşılık geldiği, kaynakta hangi bölümlerin yazılıp
yazılmadığına bağlı. Bu ders o bağlılığı ölçüyor.

## Beş Biçim, Tek Soru

Go'nun denetim akışı iki anahtar sözcüğe dayanıyor: `for` ve `switch` (`if` üçüncüsü, ama
onda yazılmayan tek şey `else`). Diğer dillerde ayrı sözcüklerle karşılanan "sonsuz döngü",
"koşullu döngü" ve "sayaçlı döngü" ayrımı, Go'da tek bir `for` sözcüğünün **hangi bölümlerinin
yazıldığına** indirgeniyor. Beş ayrı biçimi aynı çerçevede koşturuyoruz: her biri bir şeyi
yazmadan bırakıyor, dil o boşluğu kendi dolduruyor.

```go
// akis.go — bes bicim, yazilmayan parcayi tanimli bir karsilikla dolduruyor
package main

import "fmt"

func siniflandir(x int) string {
	if x < 0 {
		return "negatif"
	}
	return "negatif degil"
}

func main() {
	sayac := 0
	for {
		sayac++
		if sayac == 5 {
			break
		}
	}
	fmt.Printf("%-28s %s\n", "kosulsuz for (durana kadar)", fmt.Sprint("sayac=", sayac))

	i, toplam := 0, 0
	for i < 5 {
		toplam += i
		i++
	}
	fmt.Printf("%-28s %s\n", "tek kosullu for", fmt.Sprint("toplam=", toplam, " son_i=", i))

	puan := 72
	var not string
	switch {
	case puan >= 90:
		not = "AA"
	case puan >= 70:
		not = "BA"
	default:
		not = "FF"
	}
	fmt.Printf("%-28s %s\n", "ifadesiz switch", fmt.Sprint("not=", not))

	fmt.Printf("%-28s %s\n", "else'siz erken donus", fmt.Sprint(siniflandir(-3), " / ", siniflandir(3)))

	sonuc := ""
	switch 2 {
	case 1:
		sonuc += "bir"
	case 2:
		sonuc += "iki"
	case 3:
		sonuc += "uc"
	}
	fmt.Printf("%-28s %s\n", "switch dusmuyor", fmt.Sprint("sonuc=", sonuc))
}
```

```
kosulsuz for (durana kadar)  sayac=5
tek kosullu for              toplam=10 son_i=5
ifadesiz switch              not=BA
else'siz erken donus         negatif / negatif degil
switch dusmuyor              sonuc=iki
```

Beş satırın her biri, gövdesinden bağımsız okunabilecek bir sayıya dayanıyor. `toplam=10`,
`0+1+2+3+4`ün toplamı — döngü beş kez (`i` sıfırdan dörde) çalıştığını, `i < 5` koşulu
sağlandığı sürece devam ettiğini doğruluyor; `son_i=5` ise döngünün, koşul artık sağlanmadığı
an durduğunu gösteriyor. `not=BA`, 72 puanın `puan >= 70` dalına düştüğünü, `puan >= 90`
dalının hiç denenmediğini kanıtlıyor. Beşi de birbirinden bağımsız kanıtlar, ama hepsi aynı
soruya yanıt veriyor: yazılmayan parça neyle dolduruluyor?

**DT17.** `for`ın üç bölümü de (ilklendirme, koşul, sonlandırma) isteğe bağlıdır. İlk satırda
hiçbiri yazılmıyor; derleyici yazılmayan koşulun yerine **örtük `true`** koyuyor, bu yüzden
döngü kendiliğinden durmuyor — `sayac`, `break`e kadar sınırsız artmaya devam edeceğini
gösteriyor, biz onu beşte durduruyoruz. İkinci satırda yalnız koşul yazılıyor; ilklendirme ve
sonlandırma yazılmadığında dil onları **atlıyor**, `i`nin döngüden önce tanımlanmış ve
gövde içinde elle artırılmış olması yeterli.

İki `for` biçimi de aynı iddiayı farklı uçlardan gösteriyor: yazılmayan bir bölüm, dilin
"bu bölüm yok sayılsın" demesiyle karşılanıyor — koşul yoksa hep doğru kabul ediliyor,
ilklendirme ve sonlandırma yoksa hiç çalıştırılmıyor. Üçü de aynı `for` sözcüğünün parçası;
hangi bölümlerin yazıldığı, döngünün hangi klasik biçime (sonsuz, koşullu, üç adımlı) karşılık
geldiğini belirliyor.

Bu, `for`ın tek bir sözdizim ağacı taşıdığı, ama o ağacın üç dalının da isteğe bağlı olduğu
anlamına geliyor. Üç adımlı biçim (`for i := 0; i < 5; i++ { }`) hiçbir bölümü atlamaz ve
kaynakta en açık hâliyle durur; ikinci satırdaki tek koşullu biçim, ilklendirme ile
sonlandırmayı dışarıya, gövdenin öncesine ve içine taşır — `i, toplam := 0, 0` döngüden önce,
`i++` gövdenin son satırında. Derleyici için bu iki yazım aynı makine kodunu üretir; aradaki
fark tamamen okuyan tarafın neyi bir bakışta göreceğidir. Üç adımlı biçimde döngünün sınırları
tek satırda toplanır; tek koşullu biçimde sınırları görmek için gövdenin tamamını okumak
gerekir.

Bu ayrımın bir bedeli var: birinci satırdaki `sayac` döngüden önce sıfırlanıyor ve döngü
içinde artıyor, ama döngünün ne zaman duracağı bilgisi ne başlıkta ne de tek bir satırda —
gövdenin ortasındaki bir `if` bloğunda gizli. Koşulsuz `for`, en esnek biçimdir çünkü durma
koşulunu **hiçbir yere** sabitlemez; bu esneklik, durma koşulunu bulmak için gövdenin tamamını
okumayı gerektirir.

Bu esnekliğin bir bedeli olduğu kadar bir nedeni de var: bazı döngülerin durma koşulu, tek bir
karşılaştırmayla ifade edilemeyecek kadar karmaşıktır — birden fazla durum birlikte
sağlandığında ya da bir dış kaynaktan (bir kanaldan, bir okuyucudan) gelen bir sinyale bağlı
olarak durur. Böyle bir döngü için başlıkta tek bir koşul yazmak, gövdenin gerçek durma
mantığını başlığa **sığdırmaya** çalışmak olurdu; koşulsuz `for`, durma mantığını olduğu gibi
gövdeye bırakmanın yolu. Üç adımlı ve tek koşullu biçimler, durma koşulu tek bir karşılaştırmaya
indirgenebildiğinde tercih ediliyor; koşulsuz biçim, indirgenemediğinde.

**DT18.** Üçüncü satırda `switch` bir ifade almadan yazılıyor. Bir `switch` ifadesi
yazılmadığında derleyici onu **örtük `true`** ile karşılaştırıyor; her `case` de kendi
başına bir mantıksal ifadeye dönüşüyor. `puan >= 70` doğru olduğu için `not`, `"BA"` oluyor —
tam olarak bir `if`/`else if` zincirinin yapacağı şey, yalnız `switch` sözdizimiyle.

Bu, `switch`in Go'da bir "eşitlik" yapısından çok bir "dallanma" yapısı olduğunu gösteriyor.
Bazı dillerde `switch`, yalnız tek bir değeri sabit değerlerle eşitleyebilir; Go'da bir ifade
yazılmadığında `case`ler serbestçe mantıksal koşullar taşıyabiliyor ve bu koşullar sırayla
denenip ilk doğru olan çalıştırılıyor — tıpkı bir `if`/`else if` zincirinde olduğu gibi. Yazılan
`switch { }` ile `switch true { }` arasında hiçbir fark yok; ikincisi yalnız ilkinin yazılmayan
kısmını açıkça gösteriyor.

Bu, `switch`in iki ayrı kullanımı tek bir sözdizimde birleştirdiğini gösteriyor. Bir ifade
yazıldığında (`switch puan { case 90: ... }`), her `case` o ifadeyle **eşitlenen** bir sabit
listesi taşıyabiliyor — çoklu değer eşleşmesi bunun bir örneği, kursun ilerleyen bir dersinde
tekrar görülecek. İfade yazılmadığında ise her `case` kendi başına tam bir mantıksal ifade
taşıyor ve eşitlik değil, doğruluk sınanıyor. Aynı anahtar sözcük, yazılan tek bir parçaya
(ifadenin kendisi) bağlı olarak iki farklı dallanma biçimine dönüşüyor.

Beşinci
satırda ise farklı bir yazılmamışlık ölçülüyor: hiçbir `case` sonunda `break` yok, ama
`sonuc`, yalnız eşleşen dalın (`case 2`) değerini taşıyor — `case 3`ün gövdesi hiç
çalışmıyor. Go'da bir `case`in sonu, dalın kendiliğinden **kapanması** demek; yazılmayan
`break`in karşılığı, düşmenin **hiç olmaması**dır.

Dördüncü satır farklı bir aileden: `else` hiç yazılmadan, `if` bloğu bir `return` ile bitiyor
ve kalan kod sanki bir `else` bloğuymuş gibi çalışıyor. `siniflandir(-3)`, `if` dalına girip
`"negatif"` döndürüyor; `siniflandir(3)`, `if` dalına hiç girmeden ikinci satıra düşüp
`"negatif degil"` döndürüyor. Yazılmayan `else`nin karşılığı, kontrolün `if` bloğundan çıkan
her yolun (bir `return` ile ya da hiç girmeden) aynı yere, işlevin geri kalanına
**varmasıdır**.

Bu biçim, Go kaynaklarında "koruma cümlesi" (guard clause) diye anılan bir düzenek — bir
işlevin başında istisnai durumları erken `return` ile eleyip, geri kalan gövdeyi tek bir iç
içe geçmeden yazmanın yolu. `if x < 0 { return "negatif" }` satırından sonra `else` yazılsaydı,
işlevin geri kalanı bir kademe daha içeri kayardı; `else` yazılmadığı için ikinci `return`
işlevin ana gövdesiyle aynı girinti düzeyinde kalıyor. Yazılmayan `else`nin karşılığı bu yüzden
yalnız bir davranış değil, aynı zamanda bir **biçim** kazancı: gövde, iç içe geçmiş bloklar
yerine düz bir sırayla okunuyor.

Bu düzenek, işlev tek bir istisnai durum yerine birden fazlasını elediğinde daha da belirgin
oluyor. Art arda birkaç koruma cümlesi yazıldığında (`if a { return }`, `if b { return }`, `if
c { return }`), her biri kendi `else`sini yazsaydı gövde her satırda bir kademe daha içeri
kayardı; `else` hiç yazılmadığında bütün koruma cümleleri aynı girinti düzeyinde yan yana
durur ve işlevin "asıl işi" en sonunda, en az girintili satırda kalır. Yazılmayan `else`,
burada tek bir satırın değil, işlevin **tamamının** okunurluğünü etkiliyor.

## Sınırlayıcı Ölçüm: Yazılmayan Break, Yazılması Gereken Fallthrough

Beşinci satırdaki "düşmeme" davranışı kolaylık gibi görünüyor — bir sözcük (`break`) yazmaktan
kurtulduk. Ama tersini istediğimizde, yani bir dalın bilerek bir sonrakine düşmesini
istediğimizde, dil bunu **bedelsiz** vermiyor.

Bu ölçümün önemi, "yazılmayan bir şey her zaman en kısa yol mu" sorusuna verdiği yanıtta
yatıyor. Beşinci satırda gördüğümüz üzere, hiçbir `case` `break` yazmadı ve yine de yalnız
eşleşen dal çalıştı — bu bir kazanç gibi göründü. Ama bu kazanç, "düşme" davranışının dilde hiç
var olmadığı anlamına gelmiyor; yalnız **varsayılan olmadığı** anlamına geliyor. Aşağıdaki iki
`switch`, aynı üç dalı taşıyor ve aynı değeri (`2`) sınıyor; aralarındaki tek fark, ikincisinin
`case 2` gövdesine bir sözcük eklemesi.

```go
// sinirlayici.go — yazilmayan break gerekmiyor, ama dusmeyi isteyen kod fazladan sozcuk yaziyor
package main

import "fmt"

func main() {
	yaziliDegil := ""
	switch 2 {
	case 1:
		yaziliDegil += "bir"
	case 2:
		yaziliDegil += "iki"
	case 3:
		yaziliDegil += "uc"
	}

	yazili := ""
	switch 2 {
	case 1:
		yazili += "bir"
	case 2:
		yazili += "iki"
		fallthrough
	case 3:
		yazili += "uc"
	}

	fmt.Printf("%-28s %s\n", "break yazilmadi", fmt.Sprint("sonuc=", yaziliDegil))
	fmt.Printf("%-28s %s\n", "fallthrough yazildi", fmt.Sprint("sonuc=", yazili))
}
```

```
break yazilmadi              sonuc=iki
fallthrough yazildi          sonuc=ikiuc
```

**DT19.** İki `switch` da aynı değeri (`2`) sınıyor ve aynı üç dalı taşıyor; tek fark, ikinci
`switch`in `case 2` gövdesine `fallthrough` sözcüğünün eklenmesi. Birinci satırda sonuç yalnız
`"iki"` — `case 2` çalışıyor, `case 3`e hiç geçilmiyor. İkinci satırda sonuç `"ikiuc"` — açıkça
istenen bir düşme, `case 2`nin ardından `case 3`ü de çalıştırıyor.

Bu, "yazılmayanın karşılığı" sorusuna bir asimetri ekliyor. Varsayılan davranış (düşmeme)
hiçbir sözcük gerektirmiyor; varsayılanın **tersi** (düşme) ise adı konmuş, tek amaçlı bir
anahtar sözcük gerektiriyor. Bu asimetri kasıtlı: bir `case`in gövdesini okuyan biri, orada
`fallthrough` görmediği sürece, o dalın kendi başına bittiğinden emin olabiliyor. Yazılmayan
şey burada bir eksiklik değil, bir **garanti** — geçerli olmayan tek yorum kalıyor: dal
kendiliğinden kapanıyor, aksi yazılmadıkça.

`fallthrough`ın taşıdığı bir kısıtlama daha var: yalnız bir sonraki `case`e düşebiliyor,
kendi koşulunu **denetlemeden**. İkinci `switch`te `case 3`ün kendi koşulu (`3` değerine eşit
olmak) hiç sınanmıyor — `fallthrough` görüldüğü an, sıradaki dal koşulsuz çalıştırılıyor. Bu,
`fallthrough`ı bir `case`in **koşulunu tekrarlamak** ile karıştırmamak gerektiğini gösteriyor:
`fallthrough`, "bir sonraki dalın koşulunu da sına" değil, "bir sonraki dalın **gövdesini de**
çalıştır" demek. Yazma anında ayırt edilmesi gereken bir ayrıntı — `fallthrough`ın sıradaki
dalı sınamadan çalıştırdığını bilmeyen biri, düşen dalın koşulunun da doğrulandığını
sanabilir.

`fallthrough`ın kendi de bir kısıtla geliyor: yalnız bir `case` gövdesinin **son** satırı
olabiliyor. Bir dalın ortasına yazılsaydı derleyici bunu reddederdi — düşme, dalın geri kalanı
çalıştıktan sonra gelen tek bir geçiş, dalın içine serpiştirilebilecek bir dallanma aracı
değil. Bu kısıtlama, `fallthrough`ı sıradan bir `goto`dan ayırıyor: yalnız **bitişik** bir
sonraki dala geçebiliyor ve yalnız bir dalın en sonunda görünebiliyor.

Bu asimetri, kursun ilk dersinde ölçülen "reddetmek daha az yazmak demek değildir"
gözlemine benziyor ama ondan farklı bir yerde duruyor. Orada reddedilen bir kalıbın karşılığı
daha uzun bir yazımdı; burada hiçbir şey reddedilmiyor, yalnız **varsayılan olmayan** yol daha
uzun yazılıyor. Varsayılan davranış hep en kısa yazımı alıyor, varsayılan dışı davranış hep bir
sözcük daha fazla istiyor.

Beş biçimin tamamına birden bakıldığında ortak bir örüntü çıkıyor: Go'nun denetim akışında
yazılmayan her parça, **en sık istenen** davranışın karşılığı oluyor. Bir döngünün sonsuza
kadar sürmesi ender istenir, bu yüzden koşulsuz `for` özel bir sözdizim gerektirmiyor —
yalnız koşulun yokluğu yeterli. Bir `switch` dalının bir sonrakine düşmesi ender istenir, bu
yüzden düşmeme varsayılan; düşmek istendiğinde bu istisnai isteğin kendisi işaretlenmek
zorunda. Bir `if` bloğundan sonra kodun devam etmesi sık istenir, bu yüzden `else` yazmadan da
devam ediyor. Yazılmayan parça hep **çoğunluğun** yolu; yazılması gereken parça hep
**azınlığın** istisnası.

Beş biçimin tamamı, tek bir ölçüm programında yan yana koşturulabiliyor olması da kayda değer:
hiçbiri diğerini etkilemiyor, hiçbiri özel bir kurulum istemiyor. Bu, denetim akışının Go'da
birbirinden bağımsız, küçük kurallar kümesi olarak tasarlandığını gösteriyor — bir biçimi
anlamak için ötekileri bilmek gerekmiyor, her biri kendi başına, tek bir yazılmamışlığa tek bir
yanıt veriyor.

## Özet

- `for`ın üç bölümü de isteğe bağlı; yazılmayan koşul örtük `true`, yazılmayan ilklendirme ve
  sonlandırma yalnız atlanıyor.
- İfadesiz bir `switch`, örtük `true` ile karşılaştırılır ve her `case` kendi başına bir
  mantıksal ifadeye dönüşür.
- `if` bloğu bir `return` ile bittiğinde, `else` yazılmadan da kalan kod bir `else` bloğu gibi
  çalışır.
- Bir `switch` dalının sonu, yazılmayan bir `break`e gerek kalmadan kendiliğinden kapanır;
  beş biçimin beşi de tanımlı bir karşılıkla doluyor.
- Varsayılanın tersini (düşmeyi) istemek bedelsiz değil: `fallthrough` sözcüğü açıkça
  yazılmak zorunda.

## Sonraki Adım

Bu derste ölçülen "else'siz erken dönüş" biçimi, bir işlevin **erken** bittiği durumları
gösterdi ama işlevin dönüş değerinin kendisi hiç sorgulanmadı — `siniflandir` her zaman tek
bir dizgi döndürdü ve o dizgiyi hiç kimse yazılmadan bırakmadı. Sıradaki ders bunu soruyor: bir
işlev birden fazla değer döndürdüğünde bunlardan biri yazılmazsa ne oluyor, ve adlandırılmış
bir dönüş hiç dokunulmadan bırakıldığında hangi değeri taşıyor?
