---
title: 'Değişken Sayıda Argüman'
source: 'https://academia.sh/tr/kurslar/go-temelleri/degisken-sayida-arguman'
course: 'Go Temelleri'
language: tr
updated: '2026-08-23T14:25:01+00:00'
license: 'CC BY-SA 4.0'
---

# Değişken Sayıda Argüman

Hiç argüman verilmeyen bir değişken sayıda argüman parametresi nil bir dilim oluyor, tek tek yazılan argümanlar taze bir dilim üretiyor, mevcut bir dilimin ... ile açılması ise kopyalamadan aynı alt diziyi paylaşıyor — çağrılan tarafın yaptığı değişiklik çağırana yansıyor. Sınırlayıcı ölçüm: nil dilim ile boş dilim uzunlukça aynı ama == nil'de ayrışıyor, ve bu fark JSON karşılığında görünür oluyor.

Önceki ders, bir dönüş değerinin bir ada bağlandığında kullanılmak zorunda olduğunu ölçtü. Bu
ders aynı soruyu argüman tarafına taşıyor: bir işlev kaç argüman alacağını önceden
bilmediğinde, o parametre hiç argüman verilmediğinde ne taşıyor, ve mevcut bir dilim bu
parametreye **açılarak** geçirildiğinde aradaki ilişki nedir?

Programlama Temelleri kursu (M01/K02) değerle ve referansla aktarımı Python'la kurdu; orada
bir listeyi bir işleve geçirmek, listenin kendisini paylaşmak anlamına geliyordu. **Bu kavram
burada tekrar kurulmaz** — farkı tek cümleyle yazmak yeter: Go'da her şey değerle aktarılıyor,
dilimler de dahil; bu dersin ölçtüğü, "değerle aktarım" ile "paylaşılan bir alt diziye işaret
eden bir değerin aktarımı" arasındaki farkın değişken sayıda argümanlarda nasıl göründüğü.

## Üç Çağrı Biçimi

Go'da bir parametrenin önüne `...` konursa, o parametre **değişken sayıda argüman** kabul
eder ve işlev gövdesinde bir dilim gibi davranır. Çağıran taraf üç ayrı biçimde çağırabilir:
hiç argüman vermeden, argümanları tek tek sıralayarak, ya da elinde zaten duran bir dilimi
`...` ile açarak. Üçü de sözdizim olarak geçerli, ama imzanın arkasında üçü de aynı şeyi
üretmiyor.

Bu kursun kendisi, değişken sayıda argümanı en baştan beri kullanıyor: her `fmt.Printf` ve
`fmt.Println` çağrısı, standart kitaplığın değişken sayıda argüman alan işlevleri. Bir çağrıda
tek bir değer, başka bir çağrıda beş değer geçirebilmemiz, tam olarak bu dersin ölçtüğü
düzenek sayesinde. Bu ders, o düzeneğin kendi işlevlerimizi yazarken nasıl davrandığını
soruyor.

İki yardımcı işlev bu parametrenin davranışını iki yönden ölçüyor: `ozellikleri`, uzunluğunu
ve `nil` olup olmadığını döndürüyor; `ilkiSifirla`, ilk elemanını değiştirip bu değişikliğin
çağırana yansıyıp yansımadığını sınamamıza yarıyor.

```go
// yardimci.go — degisken sayida arguman alan iki yardimci
package main

func ozellikleri(sayilar ...int) (uzunluk int, nilMi bool) {
	return len(sayilar), sayilar == nil
}

func ilkiSifirla(sayilar ...int) {
	if len(sayilar) > 0 {
		sayilar[0] = 0
	}
}
```

**DT23.** `ozellikleri`nin dönüş imzası önceki dersin adlandırılmış dönüşünü kullanıyor;
`sayilar == nil` karşılaştırması, bir dilimin `nil` olup olmadığını sınamanın standart yolu —
Sıfır Değerler dersinde ölçülen aynı karşılaştırma burada bir parametre üzerinde koşuyor.
`ilkiSifirla` de aynı dersten bir tekniği ödünç alıyor: `len(sayilar) > 0` denetimi, `nil`
dilime indeksleme yaparak panikletmemek için — `nil` bir dilimin sıfırıncı elemanına erişmek,
tıpkı boş bir dilimde olduğu gibi, dizinin sınırları dışına taşar.

Üç çağrı biçimini yan yana koşturuyoruz: hiç argüman verilmeden, argümanlar tek tek yazılarak,
ve mevcut bir dilim `...` ile açılarak.

```go
// degisken.go — hic arguman verilmedigindeki dilim, dilimin acilmasi, acilan dilimin kopyalanmamasi
package main

import "fmt"

func main() {
	u1, n1 := ozellikleri()
	fmt.Printf("%-28s uzunluk=%d nil=%v\n", "hic arguman verilmedi", u1, n1)

	u2, n2 := ozellikleri(1, 2, 3)
	fmt.Printf("%-28s uzunluk=%d nil=%v\n", "uc arguman tek tek yazildi", u2, n2)

	kaynak := []int{10, 20, 30}
	u3, n3 := ozellikleri(kaynak...)
	fmt.Printf("%-28s uzunluk=%d nil=%v\n", "mevcut dilim acildi (...)", u3, n3)

	ilkiSifirla(1, 2, 3)
	fmt.Printf("%-28s %s\n", "tek tek yazilan degisti mi", "hicbir sey gozlenemez, cagirana ait dilim yok")

	ilkiSifirla(kaynak...)
	fmt.Printf("%-28s kaynak=%v\n", "acilan dilim degisti mi", kaynak)
}
```

```
hic arguman verilmedi        uzunluk=0 nil=true
uc arguman tek tek yazildi   uzunluk=3 nil=false
mevcut dilim acildi (...)    uzunluk=3 nil=false
tek tek yazilan degisti mi   hicbir sey gozlenemez, cagirana ait dilim yok
acilan dilim degisti mi      kaynak=[0 20 30]
```

**DT24.** İlk üç satır, aynı parametrenin üç farklı çağrı biçiminde ne taşıdığını gösteriyor.
Hiç argüman verilmediğinde (`ozellikleri()`), parametre `nil` bir dilim — uzunluğu `0` ve
kimliği boş. Argümanlar tek tek yazıldığında (`ozellikleri(1, 2, 3)`), derleyici bu üç değeri
tutacak **taze bir dilim** oluşturuyor; bu dilim `nil` değil, çünkü bir yerde gerçekten
ayrılmış. Mevcut bir dilim `...` ile açıldığında (`ozellikleri(kaynak...)`), uzunluk ve
`nil`lik ikinci satırla aynı çıkıyor — ama bu satırın asıl farkı, dördüncü ve beşinci
satırlarda ortaya çıkıyor.

Birinci satırdaki `nil` sonucu, ilk derste kurulan kalıbı doğruluyor: hiç argüman verilmemesi
bir hata değil, tanımlı bir sıfır değer. İkinci satır ise ilk kez, bir değişkenin değil, bir
**çağrının kendisinin** bir dilim ürettiğini gösteriyor — `1, 2, 3` yazmak, kaynakta hiçbir
dilim değişmezi (`[]int{1, 2, 3}`) görünmese de, çağrı anında bir dilim inşa ediyor.

İlk üç satırı yalnız `uzunluk` ve `nil` sütunlarına bakarak okursak, ikinci ve üçüncü satır
birbirinden ayırt edilemez: ikisi de `uzunluk=3 nil=false`. Bu, ölçümün bir sınırını gösteriyor
— `ozellikleri` işlevinin kendisi, kendisine geçirilen dilimin **taze** mi yoksa **paylaşılan**
mı olduğunu bilmiyor, çünkü bu bilgi dilim başlığının hiçbir alanında (uzunluk, kapasite,
işaretçi) doğrudan görünmüyor. Bu ayrımı görmek için başka bir ölçüme, `ilkiSifirla`ya
ihtiyaç var.

## Açılan Dilim Kopyalanmıyor

Bu belirsizlik, "tanımlı" sınıfının bir başka sınırını daha gösteriyor. Sekiz tanımlı satırın
her biri belirli bir soruya kesin bir yanıt veriyordu; burada soru başka — bir işlevin kendi
parametresine bakarak, o parametrenin çağıranla ne kadar bağlantılı olduğunu **anlayabilmesi**
mi soruluyor. Yanıt hayır: dilim başlığı bu bilgiyi taşımıyor, yalnız davranışı gözlemleyerek
(değiştirip sonucu izleyerek) ortaya çıkarılabiliyor.

Dördüncü ve beşinci satırlar aynı işlevi (`ilkiSifirla`) iki farklı çağrı biçimiyle
çalıştırıyor. `ilkiSifirla(1, 2, 3)` çağrısında değiştirilen dilim, yalnız o çağrı için
oluşturulmuş taze bir dilim — çağıran tarafta bu dilime karşılık gelen hiçbir değişken yok,
bu yüzden "değişti mi" sorusunun bile bir anlamı yok. `ilkiSifirla(kaynak...)` çağrısında ise
durum farklı: `kaynak`, çağrıdan önce `[10 20 30]`, çağrıdan sonra `[0 20 30]`. İşlevin içinde
`sayilar[0] = 0` yazmak, çağıranın kendi `kaynak` değişkenini değiştirdi.

**DT25.** Bu, `...` ile açılan bir dilimin **kopyalanmadığını** gösteriyor. Go, `f(dilim...)`
çağrısında yeni bir alt dizi ayırmıyor; `dilim`in kendi başlığını (uzunluk, kapasite, alt
diziye işaretçi) doğrudan parametreye geçiriyor. Parametre ile `kaynak`, aynı alt diziyi
**paylaşıyor**; parametre üzerinden yapılan bir eleman değişikliği, aynı alt diziyi okuyan
`kaynak` üzerinden de görünür oluyor.

Bu, "değerle aktarım" kuralını (Programlama Temelleri kursunda kavram olarak kuruldu, burada
tekrar kurulmuyor) çelişkili gibi gösterebilir — sanki dilim "referansla" geçiyormuş gibi
görünüyor. Ama aktarılan şey yine bir **değerdir**: dilim başlığının kendisi kopyalanıyor,
yalnız o başlığın işaret ettiği alt dizi kopyalanmıyor. `ilkiSifirla(1, 2, 3)` ile
`ilkiSifirla(kaynak...)` arasındaki fark, aktarım kuralında değil, **hangi alt dizinin**
paylaşıldığında: birincisinde parametre kendi taze alt dizisine işaret ediyor ve o alt diziyi
kimse başka bir yerden görmüyor; ikincisinde parametre `kaynak`ın **zaten var olan** alt
dizisine işaret ediyor ve o alt diziyi `kaynak` da görmeye devam ediyor.

Bu ayrım, tek tek yazılan argümanların **her zaman** güvenli olduğu, açılan bir dilimin ise
**bazen** paylaşım riski taşıdığı anlamına geliyor. `topla(1, 2, 3)` gibi bir çağrıda, işlevin
argümanları değiştirmesi hiçbir zaman çağıranı etkilemez, çünkü paylaşılacak bir çağıran-taraf
dilimi yok. `topla(dilim...)` gibi bir çağrıda ise işlevin kendi parametresine yazması,
`dilim`in kendisini de değiştirebilir. Bu, bir işlevi yazarken sorulması gereken bir soruyu
ortaya çıkarıyor: değişken sayıda argüman alan bir işlev, kendi parametresine **yazıyorsa**,
bu yazmanın çağıranı da etkileyebileceği kaynak kodunda belirtilmeli — imza bu riski kendisi
göstermiyor, çünkü `func ilkiSifirla(sayilar ...int)` imzası, `ilkiSifirla(1, 2, 3)` ile
`ilkiSifirla(kaynak...)` çağrılarının ikisi için de aynı.

Bu, standart kitaplığın değişken sayıda argüman alan işlevlerinin neden neredeyse hiçbirinin
kendi parametresine **yazmadığını** açıklıyor: `fmt.Println`, argümanlarını yalnız okuyor, hiç
değiştirmiyor. Bir işlev yazarken kendi değişken sayıda argüman parametresine yazma ihtiyacı
duyuluyorsa, bu ders bir uyarı taşıyor — o yazma, çağıranın `...` ile açtığı bir dilime
sessizce sızabiliyor.

## Sınırlayıcı Ölçüm: Nil Dilim İle Boş Dilim Aynı Değildir

İlk satırda `nil` bir dilim, ikinci ve üçüncü satırlarda `nil` olmayan dilimler gördük.
Ama `nil` olmayan bir dilim, boş da olabilir. `ozellikleri()` ile `ozellikleri([]int{}...)`
karşılaştırıldığında bu fark netleşiyor: birincisinde hiçbir argüman yok, ikincisinde bir
argüman var — o argüman, `[]int{}` ile kurulmuş, sıfır elemanlı ama gerçekten var olan bir
dilim.

```go
// sinirlayici.go — nil dilim ile bos dilim ayni degildir
package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	uNil, nNil := ozellikleri()
	uBos, nBos := ozellikleri([]int{}...)

	fmt.Printf("%-28s uzunluk=%d nil=%v\n", "hic arguman (nil dilim)", uNil, nNil)
	fmt.Printf("%-28s uzunluk=%d nil=%v\n", "bos dilim acildi ([]int{}...)", uBos, nBos)

	var nilDilim []int
	bosDilim := []int{}

	bNil, _ := json.Marshal(nilDilim)
	bBos, _ := json.Marshal(bosDilim)
	fmt.Printf("%-28s json=%s\n", "nil dilimin json karsiligi", bNil)
	fmt.Printf("%-28s json=%s\n", "bos dilimin json karsiligi", bBos)
}
```

```
hic arguman (nil dilim)      uzunluk=0 nil=true
bos dilim acildi ([]int{}...) uzunluk=0 nil=false
nil dilimin json karsiligi   json=null
bos dilimin json karsiligi   json=[]
```

İlk iki satır, `len`in ayırt edemediği bir farkı gösteriyor: ikisinin de uzunluğu `0`, ama
biri `nil`, öbürü değil. `[]int{}`, boş de olsa, bir yere **ayrılmış** bir dilim; hiçbir
elemanı yok ama kimliği var. `nil` dilim ise hiçbir yere ayrılmamış, kimliği de yok. `len` bu
ikisini ayırt etmiyor çünkü uzunluk, ayrılmış olup olmamayı değil, kaç eleman tutulduğunu
sayıyor.

Fark somut bir yerde görünüyor: `encoding/json` paketinin dönüştürücüsü. `nil` bir dilim
JSON'da `null` olarak yazılıyor, boş ama `nil` olmayan bir dilim ise `[]` olarak yazılıyor.
İkisi de "hiçbir eleman yok" bilgisini taşısa da, dönüştürücü bu iki durumu **ayrı** karşılıklar
olarak ele alıyor — biri "değer yok", öbürü "değer var ama boş". Standart kitaplığın bu
seçimi, `nil` ile boş dilim arasındaki farkı yalnız bir dil kuralı olmaktan çıkarıp, gerçek bir
programın çıktısında görünür bir sonuca dönüştürüyor.

Bu iki karşılık, aynı iki dilimin başka bir bağlamda tamamen aynı davranmasıyla da tezat
oluşturuyor. Bir `for range` döngüsüyle gezildiklerinde, `nil` dilim ile boş dilim arasında
hiçbir fark yok — ikisi de hiç yinelenmeden döngüyü bitiriyor. `append` çağrıldığında da ikisi
aynı davranıyor — ikisine de eleman eklenebiliyor. Fark yalnız **kimlik sorulduğunda**
(`== nil`) ya da **kimliğe duyarlı bir kod** (`encoding/json` gibi) devreye girdiğinde ortaya
çıkıyor. Bu, "tanımlı" sınıfının kendi içinde bir alt ayrımı daha olduğunu gösteriyor: bazı
işlemler bir dilimin kimliğine bakıyor, bazıları yalnız içeriğine.

Bu, kursun sıfır değer ölçümüne bir sınır daha ekliyor. `nil` dilim, Sıfır Değerler dersinde
ölçüldüğü gibi tanımlı bir sıfır değer taşıyor ve `append` gibi işlemlere açık. Ama `nil`
olmak ile "boş olmak" aynı şey değil, ve bu fark yalnız `== nil` karşılaştırmasında değil,
dilimi işleyen başka kodlarda (burada bir dönüştürücüde) da yüzeye çıkabiliyor. Bir işlevin
hiç argüman almadığını (`nil`) mi, yoksa boş bir dilimle çağrıldığını (`[]int{}...`) mı
bildiği, çağrılan tarafın davranışını değiştirebiliyor.

Sekiz dersin sonunda, açılış dersinde sorulan soruya geri dönebiliriz: bir dil, yazmadığın
şeyin karşılığını nasıl belirler? A payı boyunca bu soru sekiz farklı yerde soruldu — bir
kaynağın derlenebilmesi için ne gerektiğinde, bir değişkenin tipi çıkarılırken, bir sabit
dizisi doldurulurken, bir denetim yapısının parçası atlanırken, bir dönüş değeri
yazılmadığında, ve şimdi bir parametreye hiç argüman verilmediğinde. Yanıt hiçbir zaman tek
biçimli değildi: kimi zaman dil tanımlı bir değer koydu, kimi zaman derleyici kaynağı hiç
kabul etmedi, kimi zaman sonuç çalışma zamanına kaldı. Sıfır Değerler dersinde ölçülen 8/4/3
dağılımı bu üç yanıtın hiçbirinin baskın olmadığını, üçünün de dilin tasarımının bir parçası
olduğunu gösterdi.

Bu derste ölçülen `nil` dilim, o dağılımın **en görünür** üyesi, çünkü bir dilim üzerinde
neredeyse her işlem (`len`, `append`, `for range`) `nil` durumunu sorunsuzca kaldırıyor — bir
programcı `nil` bir dilimle günlerce çalışıp hiç fark etmeyebilir. Bu görünmezlik, tam da bu
dersin gösterdiği gibi, bir sınırla bitiyor: kimlik sorulduğunda ya da kimliğe duyarlı bir kod
devreye girdiğinde, `nil` olmak aniden görünür hale geliyor.

A payının sekiz dersi boyunca ölçüm hep aynı düzeni izledi: iki hâli yan yana koymak, farkı
koşturarak göstermek, sonra o farkın nerede kırıldığını bulmak. Bu son ders de aynı düzeni
taşıyor — üç çağrı biçimi yan yana koşturuldu, aralarındaki fark (paylaşım) ölçüldü, ve o
farkın kendisinin bile bir sınırı (nil ile boş dilim ayrımı) bulundu. Sıradaki konu, aynı
düzeni tek bir işlevin parametresinden bütün bir tip ailesine taşıyor.

## Özet

- Değişken sayıda argüman alan bir parametreye hiç argüman verilmezse, parametre `nil` bir
  dilim olur.
- Argümanlar tek tek yazıldığında derleyici taze bir dilim oluşturur; bu dilim `nil` değildir.
- Mevcut bir dilim `...` ile açıldığında kopyalanmaz — parametre, çağıranın dilimiyle aynı alt
  diziyi paylaşır ve çağrılan tarafın değişikliği çağırana yansır.
- `nil` dilim ile boş dilim `len` açısından aynıdır (`0`) ama `== nil` açısından ayrışır.
- Bu fark yalnız karşılaştırmada kalmıyor: `encoding/json` paketi `nil` dilimi `null`,
  boş dilimi `[]` olarak yazıyor.
- `for range` ve `append` gibi işlemler `nil` ile boş dilimi ayırt etmiyor; fark yalnız kimliğe
  bakan işlemlerde (`== nil`, `encoding/json`) ortaya çıkıyor.

## Sonraki Adım

Hiç argüman verilmeyen bir parametrenin `nil` bir dilim olması, sıfır değerin bu kursta
gördüğümüz en görünür sonucu. A payı burada kapanıyor; sıradaki konu bu tipin kendisine
bakıyor — dilim, sözlük ve yapı yazılmayanı nasıl karşılıyor, ve bir değeri bir değişkene
atadığında ortaya çıkan şey bir **kopya** mı, yoksa bu derste gördüğümüz gibi bir
**paylaşım** mı?
