---
title: 'Dilim İşlemleri'
source: 'https://academia.sh/tr/kurslar/go-temelleri/dilim-islemleri'
course: 'Go Temelleri'
language: tr
updated: '2026-08-23T14:25:00+00:00'
license: 'CC BY-SA 4.0'
---

# Dilim İşlemleri

Aynı append çağrısı, aynı kaynak metinle, iki ayrı kapasitede iki ayrı sonuç veriyor: kapasite sınırının içindeyse paylaşım sürüyor ve türetilen dilime yazmak kaynağı değiştiriyor, kapasite aşıldığında paylaşım kesiliyor ve kaynak dokunulmadan kalıyor. Bu açıklığı kapatan iki yazım var: copy ile alınan bağımsız kopya ve kapasiteyi açıkça sınırlayan üç indeksli dilimleme.

Önceki ders bir soruyla kapandı: aynı `append` çağrısı, aynı kaynak metinle, iki ayrı
kapasitede iki ayrı sonuç verir. Diziler ve Dilimler dersi paylaşımı yalnızca doğrudan
atamada gösterdi — `payDilim := kaynakDilim` gibi bir satırda. Bu ders paylaşımın daha
sık karşılaşılan biçimine bakıyor: bir dilimden **dilimlenerek** türetilen başka bir
dilime.

Dilimleme, Go kaynağında en sık görülen işlemlerden biridir: bir dosyanın satırlarını
gezerken, bir ağ paketinin başlığını gövdesinden ayırırken, bir metnin belirli bir
bölümünü alırken hep aynı sözdizim kullanılır. Bu yaygınlık, paylaşımın nasıl işlediğini
bilmemenin bedelini de büyütüyor — çünkü her dilimleme satırı, görünmeyen bir bağ
kuruyor.

## Yazılmayan Dilim Sınırlarının Varsayılanı

Bir dilimleme ifadesi `kaynak[baslangic:bitis]` biçimindedir ve iki sınırdan biri ya da
ikisi de yazılmayabilir. Sıfır Değerler dersinin ölçtüğü on beş yazılmamışlığın biri tam
olarak buydu: dilim sınırlarının yazılmaması **tanımlıdır**, başlangıç yazılmadığında
`0`'a, bitiş yazılmadığında dilimin uzunluğuna karşılık gelir.

```go
// sinirlar.go — dilimleme sinirlarinin yazilmayan uclari
package main

import "fmt"

func main() {
	kaynak := []int{10, 20, 30, 40}
	fmt.Println("kaynak[:] :", kaynak[:])
	fmt.Println("kaynak[1:]:", kaynak[1:])
	fmt.Println("kaynak[:2]:", kaynak[:2])
}
```

```
kaynak[:] : [10 20 30 40]
kaynak[1:]: [20 30 40]
kaynak[:2]: [10 20]
```

Üçü de aynı `kaynak`tan türedi ve üçü de aynı alt diziyi gösteriyor; hiçbiri kopya
almıyor. `kaynak[:]` iki sınırı da varsayılana bırakıp bütün dilimi kapsıyor, `kaynak[1:]`
yalnızca başlangıcı, `kaynak[:2]` yalnızca bitişi yazıyor. Bu üç satırın ürettiği sayılar
Sıfır Değerler dersindeki bağlayıcı tabloyla aynıdır; orada 15 yazılmamışlığın 8'i
**tanımlı** sınıfına giriyordu ve dilim sınırları bunlardan biriydi.

Yazılmayan bir sınırla, **yanlış yazılmış** bir sınır aynı şey değildir. Bitiş boş
bırakıldığında dilimin uzunluğuna düşüyordu; bitiş açıkça yazılıp kapasiteyi aştığında ise
sonuç tanımlı bir değer değil, bir çalışma zamanı durmasıdır.

```go
// asim.go — yazilmayan sinir tanimli, kapasiteyi asan sinir acikta
package main

import "fmt"

func panikliyorMu(f func()) (p bool) {
	defer func() {
		if recover() != nil {
			p = true
		}
	}()
	f()
	return false
}

func main() {
	kaynak := []int{10, 20, 30, 40}
	gecerliPanikledi := panikliyorMu(func() { _ = kaynak[1:3] })
	fmt.Println("kaynak[1:3] (gecerli aralik)      panik=", gecerliPanikledi)
	asimPanikledi := panikliyorMu(func() { _ = kaynak[1:9] })
	fmt.Println("kaynak[1:9] (kapasiteyi asan bitis) panik=", asimPanikledi)
}
```

```
kaynak[1:3] (gecerli aralik)      panik= false
kaynak[1:9] (kapasiteyi asan bitis) panik= true
```

Boş bırakılan sınır ile fazla yazılan sınır burada iki ayrı sınıfa düşüyor: birincisi
dilin kendi doldurduğu tanımlı bir değer, ikincisi derleyicinin yakalayamadığı ve çalışma
zamanına bırakılan bir hata. Aradaki fark yazılıp yazılmaması değil, yazılan değerin
kapasitenin içinde kalıp kalmamasıdır.

## Türetilen Dilime Yazmak Kaynağı Değiştirir

Dilimleme yeni bir alt dizi üretmez; türetilen dilim, kaynağın gösterdiği **aynı** alt
diziyi, farklı bir uzunluk ve başlangıç noktasıyla gösterir. Bu yüzden türetilen dilime
yazmak kaynağı da değiştirir.

```go
// turev.go — dilimlenerek turetilen dilime yazmak kaynagi degistirir
package main

import "fmt"

func main() {
	kaynak := []int{10, 20, 30, 40}
	turev := kaynak[1:3]
	turev[0] = 99
	fmt.Println("turev :", turev)
	fmt.Println("kaynak:", kaynak)
}
```

```
turev : [99 30]
kaynak: [10 99 30 40]
```

`turev := kaynak[1:3]` ikinci ve üçüncü öğeleri (`20`, `30`) kapsayan iki elemanlı bir
dilim üretiyor. `turev[0] = 99` yazıldığında değişen şey `turev`in kendi verisi değil,
`kaynak` ile paylaşılan alt dizinin ikinci öğesi; bu yüzden `kaynak[1]` de `99` oluyor. Bu,
Diziler ve Dilimler dersinde doğrudan atamada görülen paylaşımın aynısıdır — yalnızca
dilimin nasıl elde edildiği değişti, kuralın kendisi değişmedi.

Bu paylaşım ikiden fazla dilim arasında da sürüyor, çünkü hepsi aynı alt diziye bağlı
kalıyor. İki dilim kaynaktan **örtüşerek** türetildiğinde, örtüşen konuma yapılan bir yazma
ikisinden de görünüyor.

```go
// ortusen.go — kaynaktan ortusen iki dilim, ortak konuma yazma ikisinden de gorunur
package main

import "fmt"

func main() {
	kaynak := []int{10, 20, 30, 40, 50}
	sol := kaynak[0:3]
	sag := kaynak[2:5]
	sol[2] = 999 // sol'un son ogesi, kaynagin ucuncu ogesi, sag'in ilk ogesidir
	fmt.Println("sol   :", sol)
	fmt.Println("sag   :", sag)
	fmt.Println("kaynak:", kaynak)
}
```

```
sol   : [10 20 999]
sag   : [999 40 50]
kaynak: [10 20 999 40 50]
```

`sol` ilk üç öğeyi, `sag` son üç öğeyi kapsıyor; ikisi üçüncü konumda (`kaynak[2]`)
örtüşüyor. `sol[2] = 999` yazıldığında değişen tek bellek konumu, üçünün de — `sol`,
`sag` ve `kaynak`ın — paylaştığı o tek konum; bu yüzden değişiklik üçünde de görünüyor.
Kaç değişkenin aynı alt diziyi gösterdiğinin bir önemi yok, önemli olan yalnızca hangi
konumların örtüştüğü.

## Aynı Çağrı, İki Kapasite, İki Sonuç

Buraya kadarki paylaşım öngörülebilirdi: bir dilim var oldukça, ondan türetilen her dilim
onunla aynı alt diziyi paylaşıyordu. `append` bu öngörülebilirliği bozuyor, çünkü
kapasiteyi aşıp aşmadığına göre iki farklı şey yapıyor: aşmıyorsa var olan alt diziye
yazıyor ve paylaşım sürüyor; aşıyorsa yeni bir alt dizi ayırıyor ve paylaşım kesiliyor.
Kaynak metin ikisinde de birebir aynı olabiliyor.

**BT5.** — İki dilim de aynı üç öğeyle, aynı sırayla dolduruluyor; farkı yaratan tek
değişken kapasitedir. `make`e ikinci argüman olarak kapasite açıkça veriliyor ki fark
koşumdan koşuma rastlantısal olmasın.

```go
// buyume.go — ayni append cagrisi, iki kapasite, iki sonuc
package main

import "fmt"

func ekle(s []int, deger int) []int {
	return append(s, deger)
}

func main() {
	bosluklu := make([]int, 3, 5) // kapasitede iki fazladan yer var
	copy(bosluklu, []int{1, 2, 3})
	dolu := make([]int, 3, 3) // kapasitede fazladan yer yok
	copy(dolu, []int{1, 2, 3})

	bosluklu2 := ekle(bosluklu, 4)
	bosluklu2[0] = 100
	fmt.Println("bosluklu (cap=5) sonra bosluklu:", bosluklu, " bosluklu2:", bosluklu2)

	dolu2 := ekle(dolu, 4)
	dolu2[0] = 100
	fmt.Println("dolu     (cap=3) sonra dolu:", dolu, " dolu2:", dolu2)
}
```

```
bosluklu (cap=5) sonra bosluklu: [100 2 3]  bosluklu2: [100 2 3 4]
dolu     (cap=3) sonra dolu: [1 2 3]  dolu2: [100 2 3 4]
```

`ekle` işlevi ikisine de **aynı** kaynak metinle çağrıldı: `append(s, deger)`. `bosluklu`
kapasitesinde iki fazladan yer taşıyordu; `append` bu yeri kullandı, alt diziyi büyütmedi
ve döndürdüğü `bosluklu2` hâlâ aynı alt diziyi gösteriyor. Bu yüzden `bosluklu2[0] = 100`
yazıldığında `bosluklu` da değişti — paylaşım sürdü. `dolu` ise tam kapasiteydi; `append`
yeni bir alt dizi ayırdı ve `dolu2` o yeni alt diziyi gösterdi. `dolu2[0] = 100` bu kez
yalnızca `dolu2`yi değiştirdi, `dolu` dokunulmadan kaldı.

Bu, kursun en net **açıkta** kalan satırıdır: dil `append`in kapasiteyi aştığında yeni bir
alt dizi ayıracağını garanti eder, ama sonucun kaynakla paylaşılıp paylaşılmayacağını
kaynak koddan okumak mümkün değildir. Aynı satır — `append(s, deger)` — bir çağrıda
paylaşımı sürdürüyor, bir çağrıda kesiyor; okuyan biri kapasiteyi bilmeden hangisinin
olacağını söyleyemez.

Bu belirsizliğin pratikte en çok karıştığı yer, bir dilimi büyüten işlevlerdir. Bir işlev
parametre olarak aldığı dilime `append` ile öğe ekleyip sonucu geri döndürmezse, çağırandaki
değişken kapasiteye bakılmaksızın **hiç** güncellenmez — kapasite yeterliyse bile.

**BT6.** — `kap`ın kapasitesi burada bilinçli olarak bol tutuluyor (on öğelik yer, üç öğe
eklenecek); amaç kapasite yetersizliğini olası açıklamalardan çıkarmak. Kapasite dar
tutulsaydı sonucun neden değişmediği iki nedene birden bağlanabilirdi, ölçüm belirsizleşirdi.

```go
// biriktir.go — sonucu dondurmeyen append, cagirani hicbir kosulda guncellemez
package main

import "fmt"

func ekleGuvenliDegil(hedef []int, kaynak []int) {
	for _, v := range kaynak {
		hedef = append(hedef, v)
	}
	fmt.Println("islev icinde hedef:", hedef)
}

func main() {
	kap := make([]int, 0, 10) // bol kapasiteli, bos bir birikec
	ekleGuvenliDegil(kap, []int{1, 2, 3})
	fmt.Println("cagirandaki kap   :", kap)
}
```

```
islev icinde hedef: [1 2 3]
cagirandaki kap   : []
```

`kap`ın kapasitesi ondu, üç öğe için fazlasıyla yeterliydi — önceki ölçümün `bosluklu`
örneğindeki gibi paylaşım sürebilirdi. Ama `ekleGuvenliDegil` her `append` sonucunu kendi
yerel `hedef` değişkenine atıyor ve hiçbir şey geri döndürmüyor; işlev döndüğünde
`kap`ın başlığı hiç değişmemiş oluyor, `len(kap)` hâlâ sıfır. Kapasitenin yeterli olması
bile bu durumda paylaşımı kurtarmıyor, çünkü sorun alt dizide değil, güncellenen başlığın
hiçbir zaman çağırana geri taşınmamasında.

## copy ve Üç İndeksli Dilimleme: Açıklığı Kapatan İki Yazım

Bu öngörülemezlik iki yazımla kapatılabiliyor. Birincisi `copy` yerleşik işlevi: hedef ve
kaynağı ayrı alt dizilere sahip iki dilim olarak alır, öğeleri tek tek kopyalar ve kopyalanan
öğe sayısını döndürür.

```go
// kopya.go — copy ile bagimsiz kopya, uc indeksli dilimleme ile sinirli kapasite
package main

import "fmt"

func ekle(s []int, deger int) []int {
	return append(s, deger)
}

func main() {
	kaynak := []int{10, 20, 30, 40}

	bagimsiz := make([]int, len(kaynak))
	adet := copy(bagimsiz, kaynak)
	bagimsiz[0] = 7777
	fmt.Println("copy adet:", adet, " bagimsiz:", bagimsiz, " kaynak:", kaynak)

	sinirli := kaynak[1:3:3]
	fmt.Println("sinirli uzunluk=", len(sinirli), " kapasite=", cap(sinirli))
	sinirli2 := ekle(sinirli, 999)
	sinirli2[0] = 8888
	fmt.Println("sinirli2:", sinirli2, " kaynak:", kaynak)
}
```

```
copy adet: 4  bagimsiz: [7777 20 30 40]  kaynak: [10 20 30 40]
sinirli uzunluk= 2  kapasite= 2
sinirli2: [8888 30 999]  kaynak: [10 20 30 40]
```

`copy(bagimsiz, kaynak)` çağrısından sonra `bagimsiz` kendi alt dizisine sahip; ilk öğesini
değiştirmek `kaynak`ı hiç etkilemiyor. **BT7.** — Dönen `adet` değeri hiçbir yerde
varsayılmıyor, doğrudan basılıyor; `copy` hedefin ya da kaynağın uzunluğundan **küçüğünü**
kopyalar, bu örnekte ikisi de dört olduğu için dördü kopyalıyor.

`copy`nin hedef ve kaynağı bağımsız iki alt dizide olmak zorunda değil; ikisi **aynı** alt
diziyi gösterse bile doğru çalışıyor. Bu, öğeleri bir dilim içinde kaydırmak için işe
yarıyor.

```go
// kaydirma.go — copy ayni alt dizi icinde ortusen araliklarda da dogru calisir
package main

import "fmt"

func main() {
	dizi := []int{1, 2, 3, 4, 5}
	kaydirilan := copy(dizi[0:], dizi[1:4]) // son iki ogeyi bir konum sola kaydir
	fmt.Println("kaydirilan adet:", kaydirilan, " dizi:", dizi)
}
```

```
kaydirilan adet: 3  dizi: [2 3 4 4 5]
```

`dizi[1:4]` ile `dizi[0:]` aynı alt dizinin örtüşen iki dilimidir; `copy` üçüncü öğeye
kadar olan değerleri bir konum sola kaydırıyor ve son öğe (`5`) yerinde kalıyor, çünkü
kaydırma yalnızca kopyalanan üç öğeyi kapsadı. Bu davranış rastlantı değil, `copy`nin
kendi sözünün bir parçası: kaynak ve hedef örtüştüğünde bile sonuç, öğelerin sırayla değil
**doğru** kopyalandığı bir sonuçtur. Aynı işlemi tek tek dizin ilerleterek elle yazan bir
döngü, kaydırma yönüne göre öğelerin üzerine erken yazıp veriyi bozabilirdi; `copy` bu
riski taşımıyor.

İkinci yazım üç indeksli dilimlemedir: `kaynak[1:3:3]` yalnızca başlangıç ve bitişi değil,
üçüncü bir değerle **kapasiteyi** de belirtiyor. `sinirli`nin kapasitesi burada uzunluğuna
eşitleniyor — fazladan yer bırakılmıyor. Bu yüzden `sinirli`ye yapılan `append` çağrısı
**kesinlikle** kapasiteyi aşıyor ve yeni bir alt dizi ayırıyor; `sinirli2[0] = 8888`
yazıldığında `kaynak` dokunulmadan kalıyor. Önceki bölümdeki `dolu` örneğinde kapasitenin
tam olması bir rastlantıydı (üç öğelik değişmez tam üç kapasiteyle kuruldu); üç indeksli
dilimleme bunu **rastlantı olmaktan çıkarıp** bir yazım kararına dönüştürüyor — kapasiteyi
istenen sınıra kilitliyor.

**BT8.** — İki kapatma yazımı iki ayrı amaca hizmet ediyor: `copy` verinin tamamen ayrı bir
kopyasını istiyorsa kullanılır, üç indeksli dilimleme ise kaynakla aynı alt diziyi paylaşmayı
sürdürüp yalnızca sonraki bir `append`in paylaşımı kesmesini **garanti altına almak**
istendiğinde kullanılır. Birincisi paylaşımı baştan bitirir, ikincisi paylaşımı büyümenin
keseceğini önceden belirler.

Bu iki yazımın ortak noktası, ikisinin de kapasiteyi kod okuyucusunun tahminine
bırakmaması. `copy` kapasiteyi konudan tamamen çıkarıyor — hedefin kendi kapasitesi neyse
o kullanılıyor, kaynağınkiyle hiçbir ilişkisi kalmıyor. Üç indeksli dilimleme ise kapasiteyi
sıfırlamıyor, tam tersine onu **daraltıyor**: normalde `kaynak[1:3]` yazımı kalan bütün
kapasiteyi (kaynağın sonuna kadar) devralırdı, üçüncü indeks bu devralmayı keserek dilimi
kendi büyüklüğüne hapsediyor. İkisi de aynı sonuca varıyor — sonraki bir `append`in kaynağa
dokunmayacağından emin olmak — ama farklı maliyetlerle: `copy` bir kopyalama işlemi
gerektirir, üç indeksli dilimleme hiçbir veri taşımaz, yalnızca bir sayıyı sınırlar.

Üç bölümün ölçtüğü şey tek bir cümleye iniyor: dilimleme her zaman paylaşır, `append`
kapasiteye göre paylaşır ya da paylaşmaz, `copy` ve üç indeksli dilimleme ise paylaşımı
yazım düzeyinde bir karara dönüştürür. Kaynak metne bakarak "bu satır paylaşıyor mu"
sorusunun yanıtı, üçüncü durumda önceden bilinir; ilk ikisinde bilinmez, yalnızca
koşturularak öğrenilir.

## Özet

- Dilimleme ifadesinin yazılmayan sınırları tanımlıdır: başlangıç yazılmazsa `0`, bitiş
  yazılmazsa dilimin uzunluğu kullanılır; bu, Sıfır Değerler dersindeki bağlayıcı 8/4/3
  dağılımının tanımlı sınıfına giren bir örnektir.
- Dilimlemeyle türetilen bir dilim kaynakla aynı alt diziyi gösterir; türetilen dilime
  yazmak kaynağı da değiştirir.
- `append` kapasiteyi aşmadığı sürece var olan alt diziye yazar ve paylaşım sürer;
  kapasiteyi aştığında yeni bir alt dizi ayırır ve paylaşım kesilir. Aynı kaynak metin iki
  ayrı kapasitede iki ayrı sonuç verebilir.
- `copy` hedefe ait bağımsız bir alt diziye öğeleri tek tek kopyalar ve kopyalanan öğe
  sayısını döndürür; kaynakla hiçbir paylaşım bırakmaz.
- Üç indeksli dilimleme (`kaynak[baslangic:bitis:kapasite]`) kapasiteyi açıkça sınırlar ve
  sonraki bir `append`in kaynaktan ayrılacağını yazım düzeyinde garanti eder.

## Sonraki Adım

Bu iki derste ölçülen paylaşım dizi ve dilim gibi sıralı yapılar arasındaydı; sıradaki
konu anahtar-değer eşleşmesine bakıyor. Sözlük de bir başlıktır ve bir alt yapıyı
paylaştırır, ama sorduğu soru farklıdır: olmayan bir anahtara erişildiğinde ne olur, ve bu
yanıt tek bir değerle mi yoksa iki değerle mi geliyor? Sıradaki ders bu ikisini ayırıyor —
ve gezinme sırasının neden hiçbir zaman doğrudan yazdırılmadığını da.
