---
title: Fonksiyonlar
source: 'https://academia.sh/tr/kurslar/go-temelleri/fonksiyonlar'
course: 'Go Temelleri'
language: tr
updated: '2026-08-23T14:25:00+00:00'
license: 'CC BY-SA 4.0'
---

# Fonksiyonlar

Adlandırılmış bir dönüş değerine hiç dokunulmadığında tipinin sıfır değerini taşıyor; bir dönüş değerinin hiç yazılmaması derleme zamanında reddediliyor, ama çağıranın döneni hiç yakalamadan yok sayması hiçbir şey demiyor — Go'da hata bir dönüş değeri olduğu için bu açıkta kalan davranış kursun en önemli örneği. Sınırlayıcı ölçüm: dönüş değeri değişkene alınıp kullanılmadığında bu açıklık kapanıyor ve kullanılmayan değişken reddi devreye giriyor.

Önceki ders "else'siz erken dönüş"ü ölçtü ama işlevin döndürdüğü değerin kendisine hiç
bakmadı. Bu ders o değere bakıyor: bir işlev birden fazla değer döndürdüğünde bunlardan biri
yazılmazsa ne oluyor, adlandırılmış bir dönüş hiç dokunulmadan bırakıldığında hangi değeri
taşıyor, ve çağıran taraf dönen değeri hiç yakalamazsa dil buna ne diyor?

Programlama Temelleri kursu (M01/K02) fonksiyon tanımını Python'la kurdu; orada bir işlev tek
bir değer döndürüyordu ya da hiç döndürmüyordu, birden fazla değer bir demet olarak paketlenip
tek bir dönüş yuvasından geçiyordu. **Bu kavram burada tekrar kurulmaz** — farkı tek cümleyle
yazmak yeter: Go'da çoklu dönüş, imzanın **kendisinin** parçasıdır; bir demete paketlenmez,
her değer kendi tipiyle ayrı ayrı yazılır. Bu ders, bu ayrı yuvaların yazılmadığında ne
taşıdığını ölçüyor.

## Çoklu Dönüş Değeri ve Adlandırılmış Dönüşün Sıfırı

Go'da bir işlev birden fazla değer döndürebiliyor ve bu değerler **adlandırılabiliyor** —
imzada yazılan adlar, işlevin gövdesinde sıradan birer değişken gibi kullanılabiliyor. `bol`
işlevi bunu gösteriyor: `sonuc` ve `hata`, `func` satırında adlandırılmış, gövdede hiç
`return sonuc, hata` yazılmadan, çıplak bir `return` ile dönüyor.

Sıfır değerler dersinde ölçülen `adliDonus` işlevi bu davranışı zaten bir satırda göstermişti:
`func adliDonus() (sonuc int, hata error) { return }`, hiçbir gövde çalıştırmadan iki sıfır
değeri dönüyordu. Bu ders aynı düzeneği, gövdesi gerçekten çalışan, koşula göre dallanan bir
işlevde ölçüyor — `bol`, iki farklı yoldan geçebiliyor ve her yolda adlandırılmış dönüşün ne
kadarına dokunulduğu değişiyor.

```go
// fonksiyon.go — coklu donus degeri ve adlandirilmis donusun yazilmadiginda sifir donmesi
package main

import "fmt"

func bol(a, b int) (sonuc int, hata error) {
	if b == 0 {
		hata = fmt.Errorf("sifira bolme")
		return
	}
	sonuc = a / b
	return
}

func main() {
	s1, h1 := bol(10, 2)
	fmt.Printf("%-24s sonuc=%v hata=%v\n", "basarili bolme", s1, h1)

	s2, h2 := bol(10, 0)
	fmt.Printf("%-24s sonuc=%v hata=%v\n", "sifira bolme", s2, h2)

	bol(10, 0)
	fmt.Printf("%-24s %s\n", "yok sayilan cagri", "panik yok, program devam ediyor")
}
```

```
basarili bolme           sonuc=5 hata=<nil>
sifira bolme             sonuc=0 hata=sifira bolme
yok sayilan cagri        panik yok, program devam ediyor
```

**DT20.** `b == 0` dalında yalnız `hata`ya değer atanıyor, `sonuc`a hiç dokunulmuyor.
Yazdırılan `sonuc=0`, kaynakta hiçbir yerde `sonuc = 0` yazılmadığı hâlde çıkıyor — `int`in
sıfır değeri, Sıfır Değerler dersinde ölçülen çerçevenin doğrudan bir uzantısı. Adlandırılmış
bir dönüş değeri, işlev başladığı anda kendi tipinin sıfır değeriyle **önceden ilklendirilmiş**
bir yerel değişken gibi davranıyor; gövde ona hiç dokunmazsa, döndürdüğü şey o ilk değerdir.

Bu ilklendirme, işlev çağrıldığı **her seferinde** tazeleniyor. `bol(10, 2)` ve `bol(10, 0)`
aynı işlevin iki ayrı çağrısı ve ikisinde de `sonuc` sıfırdan başlıyor; birinci çağrıda `5`e
atanıyor, ikincisinde hiç atanmadığı için sıfırda kalıyor. Bir önceki çağrının `sonuc`u,
sıradaki çağrıyı hiçbir şekilde etkilemiyor — her çağrı, adlandırılmış dönüşlerini kendi sıfır
değerleriyle taze başlatıyor.

İkinci satır bunu daha da netleştiriyor: `hata` atandığı için `hata=sifira bolme` görünüyor,
ama `sonuc` hâlâ `0`. İki değer aynı `return` ifadesiyle dönüyor, ama yalnız biri kaynakta
elle yazıldı. Adlandırılmış dönüş, çoklu dönüş değerinin **bazılarını** yazıp geri kalanını
sıfır değerine bırakmanın yolunu açıyor — imzada iki ad birden görünse de, gövdenin ikisine de
dokunması zorunlu değil.

Çıplak `return` (`return sonuc, hata` yerine yalnız `return`) burada bir kısaltmadan fazlası.
Adlandırılmamış bir çoklu dönüşte her `return` ifadesi, dönecek değerleri açıkça sıralamak
zorundadır; adlandırıldığında, kaynakta iki kez tekrar edecek adları yazmadan, işlevin o anki
durumunu olduğu gibi dönmek mümkün oluyor. Bu, `sonuc` ve `hata`nın işlev boyunca **paket
düzeyi değil yerel** değişkenler gibi davrandığını gösteriyor — imzada bildirilmiş olsalar
da, gövdenin herhangi bir noktasında okunabilir ve değiştirilebilirler.

Adlandırmanın bir de belgeleme yanı var. `func bol(a, b int) (int, error)` yazılsaydı, imza
yalnız iki tipi bildirirdi; hangi değerin sonucu, hangisinin hatayı taşıdığını anlamak için
gövdeyi okumak gerekirdi. `sonuc` ve `hata` adlarının imzada yazılması, bu bilgiyi gövdeye
inmeden veriyor — imza kendi başına, hangi dönüş yuvasının neyi taşıdığını söylüyor. Bu
yüzden adlandırılmış dönüşler, kısa bildirimin tam tersi bir yönde çalışıyor: kısa bildirim
tip adını **kaldırıyordu**, adlandırılmış dönüş bir **anlam adı ekliyor**.

Bu belgeleme kazancı, adlandırmanın **zorunlu olmamasıyla** birlikte okunmalı. `func bol(a, b
int) (int, error)` da geçerli bir imzadır ve tamamen aynı şekilde iki değer döndürür;
adlandırma yalnız okunabilirlik için tercih ediliyor, davranışı değiştirmiyor. Bir işlevin
adlandırılmış dönüşe ihtiyacı olup olmadığı, kaç değer döndürdüğüne değil, o değerlerin
anlamının imzadan ne kadar açık okunduğuna bağlı.

## Yazılmayan Dönüş Değeri Reddediliyor, Kullanılmayan Değil

İlk derste ölçülen dört retten biri, dönüş değerinin **yazılmamasıydı**: `func F() int { }`
gövdesi hiçbir değer üretmeden bitiyordu ve derleyici bunu reddediyordu. Bu ders o reddin tam
tersini ölçüyor: dönüş değerini **çağıran tarafın** hiç kullanmaması aynı şekilde reddediliyor
mu? Sezgisel olarak "hayır" denebilir — bir işlevi çağırıp sonucunu kullanmamak, birçok
bağlamda tamamen sıradan bir işlem (bir günlük yazma çağrısının dönüşü genelde önemsizdir). Bu
ders sezgiyi değil, gerçek davranışı ölçüyor.

Üçüncü satır bu soruyu koşturarak yanıtlıyor. `bol(10, 0)` çağrısı, hiçbir değere atanmadan,
tek başına bir ifade olarak yazılıyor — iki dönüş değeri de (sonuç ve hata) sessizce
atılıyor. Program panik yapmıyor, derleyici hiçbir şey söylemiyor, çalıştırma normal şekilde
devam ediyor.

**DT21.** Bu satırda hiçbir değişken tanımlanmıyor — yalnız bir çağrı yapılıyor. İlk derste
ölçülen "kullanılmayan değişken" reddi, tanımlanan bir adın hiç okunmamasına uygulanıyordu;
burada tanımlanan hiçbir ad yok, o yüzden o kural devreye hiç girmiyor. Dönen iki değer,
hiçbir yere yazılmadan, çağrının kendisiyle birlikte kayboluyor.

Bu, ilk derste ölçülen dört retle bir arada okunduğunda çarpıcı bir asimetri ortaya çıkarıyor.
`func F() int { }` gibi bir gövde, dönüş değerini **yazmadığı** için reddediliyordu — derleyici
imzanın verdiği sözü tutmayan bir gövdeyi kabul etmiyordu. Ama `bol(10, 0)` çağrısı, dönüş
değerini fazlasıyla **üretiyor** — işlev sözünü tutuyor, iki değer de hesaplanıyor — yalnız
çağıran taraf bu üretilmiş değerleri hiç talep etmiyor. Derleyicinin ilgisi üretimin
kendisiyle sınırlı; üretilen bir değerin sonradan ne olduğu, işlevin sınırları dışında kalan
bir mesele.

Bu, kursun **açıkta** sınıfının şimdiye kadarki en önemli örneği, çünkü Go'da hata bir
sıradan **dönüş değeridir** — ayrı bir mekanizma, bir istisna türü ya da zorunlu bir
yakalama yapısı yok. Bir işlev bir `error` döndürüyorsa, bu değeri okuyup okumamak tamamen
çağıran tarafın kararı. Dil, dönen bir hatanın kontrol edilmesini **hiçbir şekilde**
zorunlu kılmıyor; `bol(10, 0)`ın döndürdüğü hata, tıpkı bir günlüğe hiç yazılmamış bir olay
gibi sessizce yok oluyor.

Bu davranışın kaynakta hiçbir izi de kalmıyor. Üçüncü satırın çıktısı ("panik yok, program
devam ediyor") bunu doğruluyor: `sifira bolme` hatası gerçekten üretiliyor, ama hiçbir yere
yazılmadığı için hiçbir etkisi olmuyor — ne bir panik, ne bir günlük satırı, ne bir çıkış
kodu değişikliği. Kaynağı okuyan biri, `bol(10, 0)` satırına bakarak bu çağrının bir hata
üretip üretmediğini bile göremez; bunu anlamak için işlevin **tanımına** bakmak gerekiyor.
Bu, açıkta kalan davranışın ortak özelliği: sonucu görmek için çağrı satırı yetmiyor,
tanımın kendisi okunmak zorunda.

## Sınırlayıcı Ölçüm: Yok Sayılan Her Zaman Açıkta Kalmaz

Bu açıklığın bir sınırı var. Dönen değerleri **hiç yakalamadan** yok saymak serbestken, onları
bir değişkene **alıp** sonra kullanmamak serbest değil. Bunu ölçmek için ilk dersteki
derleyici çağrısına dönüyoruz ve `bol`u iki farklı kaynak parçasında çağırıyoruz — biri
sonuçları hiç yakalamıyor, öbürü yakalayıp yalnızca birini kullanıyor.

```go
// derleyici.go — derleyiciyi program icinden cagiran yardimci
package main

import (
	"os"
	"os/exec"
	"path/filepath"
)

func derlenirMi(kaynak string) bool {
	dizin, err := os.MkdirTemp("", "sinama")
	if err != nil {
		return false
	}
	defer os.RemoveAll(dizin)
	os.WriteFile(filepath.Join(dizin, "go.mod"), []byte("module sinama\n\ngo 1.24\n"), 0o644)
	os.WriteFile(filepath.Join(dizin, "kod.go"), []byte(kaynak), 0o644)
	cmd := exec.Command("go", "build", "./...")
	cmd.Dir = dizin
	cmd.Env = append(os.Environ(), "GOTOOLCHAIN=local")
	return cmd.Run() == nil
}

func sinif(ok bool) string {
	if ok {
		return "derlendi"
	}
	return "derlenmedi"
}
```

```go
// sinama.go — tumuyle yok saymak ile degiskene alip yari kullanmamak ayni sey degil
package main

import "fmt"

func main() {
	tumuyleYokSayilan := `package sinama
import "fmt"
func bol(a, b int) (sonuc int, hata error) {
	if b == 0 {
		hata = fmt.Errorf("sifira bolme")
		return
	}
	sonuc = a / b
	return
}
func F() { bol(10, 2) }`

	yariYokSayilan := `package sinama
import "fmt"
func bol(a, b int) (sonuc int, hata error) {
	if b == 0 {
		hata = fmt.Errorf("sifira bolme")
		return
	}
	sonuc = a / b
	return
}
func F() { s, h := bol(10, 2); _ = s }`

	fmt.Printf("%-34s %s\n", "tumuyle yok sayilan", sinif(derlenirMi(tumuyleYokSayilan)))
	fmt.Printf("%-34s %s\n", "degiskene alinip yari kullanilan", sinif(derlenirMi(yariYokSayilan)))
}
```

```
tumuyle yok sayilan                derlendi
degiskene alinip yari kullanilan   derlenmedi
```

**DT22.** İki kaynak da aynı `bol` işlevini çağırıyor ve aynı sonucu (hata) yok sayıyor;
aradaki tek fark, ikinci kaynağın dönen değerleri `s` ve `h` adlı değişkenlere **alması**.
Birinci kaynakta hiçbir ad tanımlanmadığı için kullanılmayan değişken reddi hiç devreye
girmiyor. İkinci kaynakta `h` adı tanımlanıyor ve hiç okunmuyor — `_ = s` yalnız `s`yi
kurtarıyor, `h` kullanılmayan değişken kalıyor ve derleme reddediliyor.

Bu, "açıkta" sınıfının sınırını netleştiriyor. Bir dönüş değerini yakalamamak, dilin hiçbir
zaman göremeyeceği bir karardır — çağrı satırında hiçbir ad yok, denetlenecek bir şey yok.
Ama bir kez bir ada bağlandığında, o ad artık ilk derste ölçülen kuralın kapsamına giriyor:
yazılan her ad ya kullanılmalı ya da kaynakta hiç yazılmamalı. Hatanın kendisi "açıkta"
kalmaya devam ediyor — dil hâlâ onu okumanızı zorunlu kılmıyor — ama onu bir **ada** bağlayıp
sonra unutmak, farklı bir kurala takılıyor.

Bu ayrım, Go'da hata denetiminin neden çoğunlukla `sonuc, hata := bol(...)` biçiminde
yazıldığını da açıklıyor. `hata` bir değişkene alındığı anda, onu hiç okumadan bırakmak
derlemeyi durduruyor — `if hata != nil` yazmak bir stil tercihi değil, `hata` adını
**kullanılmış** saymanın en doğal yolu. Dönüş değerini yakalamadan tamamen görmezden gelmek
hâlâ mümkün, ama bir kez yakalandığında görmezden gelmek artık mümkün değil.

Bu, kaynağı okuyan biri için de bir işaret taşıyor: bir çağrının sonucu hiç yakalanmadıysa,
o çağrının hatasının hiç denetlenmediği kesin — ama bir sonuç yakalandıysa, o sonucun en
azından **derlenebilir olacak kadar** kullanıldığı da kesin. Kullanım, denetim anlamına
gelmiyor — `_ = h` yazıp `h`yi hiç okumadan da "kullanılmış" sayılabilirdi — ama en azından
adın kaynakta bir amaçla durduğunu gösteriyor. Bu, ilk derste ölçülen boş tanımlayıcının
üçüncü bir kullanımı: `_ = h` yazmak, "bu hatayı biliyorum ama bilerek denetlemiyorum" demenin
yazılı biçimi. Kullanılmayan değişken reddi, bir hatayı **denetlemeye** zorlamıyor — yalnız
onu **isimlendirip unutmaya** izin vermiyor.

Aradaki fark küçük görünse de pratikte önemli: bir kod tabanında hangi hataların hiç
yakalanmadığını bulmak için çağrı satırlarını taramak gerekir (derleyici burada hiçbir iz
bırakmaz), ama hangi yakalanmış hataların denetlenmediğini bulmak biraz daha kolaydır — en
azından `_ = hata` gibi bilinçli bir görmezden gelme izini aramak mümkündür. Derleyici birinci
grubu hiç göremiyor, ikinci grubu da yalnız "kullanılmadı mı" sorusuyla görüyor, "denetlendi
mi" sorusuyla değil.

Bu dersin üç ölçümü — adlandırılmış dönüşün sıfırı, yazılmayan dönüşün reddi, kullanılmayan
dönüşün açıklığı — kursun üç sınıfının üçünü de tek bir işlev üzerinde gösteriyor. `bol`un
kendisi hiç değişmedi; değişen, onu **nasıl çağırdığımız**. Aynı işlev, adlandırılmış bir
dönüşle çağrıldığında tanımlı bir sıfır değer taşıyor, imzasız bırakıldığında derlemeyi
durduruyor, çağrıda yakalanmadan bırakıldığında sessizce kayboluyor. Yazılmayanın karşılığı,
bu derste ilk kez işlevin **kendisine** değil, işlevin **çağrılma biçimine** bağlı hâle
geliyor.

Üç ölçümü bir arada okuduğumuzda, Go'nun fonksiyon tasarımının aynı ilkeyi üç kere tekrarladığı
görülüyor: **üretim** zorunlu, **tüketim** değil. Bir işlev, imzasının söz verdiği her değeri
üretmek zorunda — ya elle yazarak ya da adlandırılmış dönüşün sıfırına güvenerek. Ama o
üretilmiş değeri çağıran tarafın **alması**, dilin hiçbir zaman zorunlu kıldığı bir şey değil.
Yalnız bir kez alındığında, artık o alınan şeyin de kaynakta bir amaca hizmet etmesi gerekiyor.

## Özet

- Adlandırılmış bir dönüş değerine gövde hiç dokunmazsa, o değer kendi tipinin sıfır değerini
  taşır — `sonuc=0`, kaynakta hiçbir yerde `sonuc = 0` yazılmadan çıkıyor.
- Bir dönüş değerinin hiç yazılmaması (`func F() int { }`) derleme zamanında reddediliyor.
- Çağıranın dönen değerleri hiç yakalamadan yok sayması hiçbir şekilde reddedilmiyor — Go'da
  hata bir dönüş değeri olduğu için bu, kursun en önemli açıkta örneği.
- Dönen değerler bir değişkene alındığında durum değişiyor: kullanılmayan değişken reddi
  devreye giriyor ve yarım kullanım artık derlenmiyor.
- Hatanın kendisi hep açıkta kalıyor; onu bir ada bağlayıp sonra unutmak farklı, ayrı bir
  kurala takılıyor.
- Fonksiyon tasarımının ilkesi tek: bir işlev söz verdiği her değeri üretmek zorunda, ama
  çağıran tarafın o değeri alması dilin hiçbir zaman zorunlu kıldığı bir şey değil.

## Sonraki Adım

Bu derste `bol` işlevi hep iki sabit argümanla çağrıldı ve dönüş tarafındaki yazılmamışlıklar
ölçüldü — argüman tarafında hiçbir belirsizlik yoktu, imza kaç argüman istediğini kesin olarak
söylüyordu. Ama bazı işlevler kaç argüman alacağını önceden bilmiyor — çağıran taraf sıfır, bir
ya da yirmi değer geçebiliyor. Sıradaki ders, A payının son dersi, bu belirsizliği ölçüyor:
değişken sayıda argüman alan bir parametre, hiç argüman verilmediğinde ne oluyor, ve bu
dersin kurduğu "yakalanan değerin adı" ile bir dilimin kendisi arasında nasıl bir ilişki var?
