---
title: 'Genel Veri Yapıları'
source: 'https://academia.sh/tr/kurslar/go-tip-sistemi/genel-veri-yapilari'
course: 'Arayüzler, Hatalar ve Genellikler'
language: tr
updated: '2026-08-23T14:25:02+00:00'
license: 'CC BY-SA 4.0'
---

# Genel Veri Yapıları

Bir genel veri yapısının tip parametresi çağıranın bildiriminde açıkça yazılır: Yigin[int] ile Yigin[string] %T'de iki ayrı dinamik tip olarak görünüyor ve biri diğerinin yerine geçemiyor. Tip güvenliğinin ölçülebilir karşılığı: boş arayüzle yazılan aynı yapıda elemanı kullanmak için bir tip iddiası gerekirken genel yapıda sıfır. Sınırlayıcı ölçüm, karşılaştırılabilirliğin hem kapsayıcının kendi alan yapısına hem tip parametresinin kendisine bağlı olduğunu gösteriyor.

Tip Kısıtları dersi bir bağın iki katmanda kurulduğunu gösterdi: kısıtın izin verdiği
işlemler bildirimde durur, o işlemlerin hangi somut tip için çalışacağı kullanım yerinde
kurulur. Bu ders aynı iki katmanı bir veri yapısı üzerinde ölçer, ama bir farkla: bir genel
fonksiyonun tip parametresi çağrı yerinde **çıkarılıyordu**, kaynakta hiç yazılmıyordu.
Bir genel veri yapısının tip parametresi ise çağıranın kendi bildiriminde **açıkça
yazılır** — `Yigin[int]` diyen taraf, `[int]`i kendi eliyle koyar, derleyici bunu bir
argümandan okumaz. Aynı soru, iki farklı yanıt: bağ yine kaynağın dışında (fonksiyonun
kendi tanımının dışında) kuruluyor, ama bu kez çıkarımla değil, çağıranın yazdığı bir
bildirimle.

Bu farkın kaynağı, bir fonksiyon çağrısıyla bir tip bildirimi arasındaki farkla aynı yerde
duruyor. Bir fonksiyon çağrısında argümanlar zaten var — derleyici onların tipine bakıp
`T`yi çıkarabiliyor. Bir tip bildiriminde ise henüz hiçbir argüman yok; `Yigin[int]` bir
değer değil, bir **tip adı**, ve bir tip adının hangi tip parametresiyle örnekleneceğini
çıkaracak bir argüman ortada bulunmuyor. Derleyicinin çıkarım yapabilmesi için okuyacağı
bir şeye ihtiyacı var; genel fonksiyonda bu, çağrının argümanlarıdır, genel tipte ise
böyle bir argüman yok — çağıranın kendisi yazmak zorunda.

## Örnekleme Çağıranın Bildiriminde Duruyor

Bir genel veri yapısı, adının hemen ardına bir tip parametresi listesi ekleyen bir tip
bildirimidir: `type Yigin[T any] struct{ ogeler []T }`. Bu tek kaynak, `Yigin[int]`
için de `Yigin[string]` için de kullanılabilir bir **tip güvenli kapsayıcı** kalıbı
kurar — ama kullanılabilmesi için önce **örneklenmesi** gerekir, ve bu örnekleme her
zaman kullanan tarafın kendi bildiriminde yazılıdır: bir değişken tanımında, bir alan
tipinde ya da bir dönüş tipinde.

`Yigin`in yöntemleri kendi tip parametresini yeniden tanımlamıyor; alıcı yazımındaki
`(y *Yigin[T])` ifadesi, tipin kendi bildiriminde açılmış olan `T`yi yönteme **taşıyor**.
`Ekle(o T)` ve `Tepe() (T, bool)` bu yüzden yeni bir köşeli parantez açmıyor — kullandıkları
`T`, `Yigin`in kendisiyle birlikte, `Yigin[int]` örneklendiği anda zaten `int`e
bağlanmış oluyor. Örnekleme bir kez, tipin kendi bildiriminde oluyor; o tipe bağlı her
yöntem bu tek örneklemeyi paylaşıyor.

```go
// yigin.go — genel veri yapisinin ornek(leme)si cagiranin bildiriminde
package main

import "fmt"

type Yigin[T any] struct{ ogeler []T }

func (y *Yigin[T]) Ekle(o T) { y.ogeler = append(y.ogeler, o) }

func (y *Yigin[T]) Tepe() (T, bool) {
	var sifir T
	if len(y.ogeler) == 0 {
		return sifir, false
	}
	return y.ogeler[len(y.ogeler)-1], true
}

func main() {
	var tamsayiYigini Yigin[int]
	tamsayiYigini.Ekle(3)
	tamsayiYigini.Ekle(5)

	var dizgiYigini Yigin[string]
	dizgiYigini.Ekle("elma")

	t, _ := tamsayiYigini.Tepe()
	d, _ := dizgiYigini.Tepe()

	fmt.Printf("%-24s tip=%-16T deger=%v\n", "tamsayiYigini", tamsayiYigini, t)
	fmt.Printf("%-24s tip=%-16T deger=%v\n", "dizgiYigini", dizgiYigini, d)
	fmt.Println("sonuc uzerinde aritmetik:", t+1)
}
```

```
tamsayiYigini            tip=main.Yigin[int]  deger=5
dizgiYigini              tip=main.Yigin[string] deger=elma
sonuc uzerinde aritmetik: 6
```

**GN9.** `var tamsayiYigini Yigin[int]` satırının kendisi, `T`nin `int` olacağını
söyleyen bir **bildirimdir** — Genel Fonksiyonlar dersindeki `ilkOge(tamsayilar)` çağrısıyla
karşılaştırıldığında fark açık: orada `T`nin ne olduğu argümanın tipinden **çıkarılıyordu**
ve kaynakta hiçbir yerde `int` yazmıyordu; burada `int` satırın içinde, gözle görülür
biçimde duruyor. `%T` bunu doğruluyor: `tamsayiYigini` ile `dizgiYigini` aynı kaynaktan
üretildi, ama çalışma zamanındaki dinamik tipleri `main.Yigin[int]` ve
`main.Yigin[string]` — birbirinden tamamen ayrı iki tip, tıpkı `[4]int` ile `[3]int`in
ayrı tip olması gibi (Diziler ve Dilimler, M09/K01). Ortak ölçümde bu bağ "genel tipin
örneklenmesi" adıyla bildirim örneklerinden biri sayılıyor.

`var tamsayiYigini Yigin[int]` satırının bir çağrı içermediğine de dikkat etmek gerekir —
bu bir sıfır değer bildirimi, `New` benzeri bir yapıcı çağrılmıyor. Sıfır Değerler dersinin
(M09/K01) ölçtüğü gibi, bir yapının sıfır değeri kendi alanlarının sıfır değerlerinden
kuruluyor: `ogeler` alanı burada `nil` bir dilim olarak başlıyor. Bu, örnekleme ile ilk
değerin verilmesi arasındaki farkı gösteriyor: `Yigin[int]` yazmak `T`yi bağlıyor, ama
`ogeler`i doldurmuyor; ilk `Ekle` çağrısı `append`i `nil` bir dilim üzerinde çalıştırıyor
ve Değişken Sayıda Argüman dersinin (M09/K01) ölçtüğü gibi bu sorunsuz işliyor — `nil`
dilime eklemek onu büyütüyor, panikletmiyor.

## Tip Güvenliğinin Ölçülebilir Karşılığı

İki örneklemenin ayrı tip olması bir sonuç doğuruyor: biri diğerinin yerine
**geçemiyor**. Aşağıdaki ölçüm bunu, ve aynı işi boş arayüzle yazmanın bedelini,
derleyiciye sorarak sayıyor.

```go
// guvenlik.go — tip guvenliginin olculebilir karsiligi: kac tip iddiasi gerekiyor
package main

import (
	"fmt"
	"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 siniflaKaynak(kaynak string) string {
	if derlenirMi(kaynak) {
		return "derlendi"
	}
	return "derlenmedi"
}

func main() {
	yerDegistirme := `package sinama
type Yigin[T any] struct{ ogeler []T }
func F() {
	var a Yigin[int]
	var b Yigin[string]
	b = a
	_ = b
}`

	anySizIddia := `package sinama
type YiginAny struct{ ogeler []any }
func (y *YiginAny) Ekle(o any) { y.ogeler = append(y.ogeler, o) }
func (y *YiginAny) Tepe() any { return y.ogeler[len(y.ogeler)-1] }
func F() {
	var y YiginAny
	y.Ekle(3)
	t := y.Tepe()
	_ = t + 1
}`

	anyIleIddia := `package sinama
type YiginAny struct{ ogeler []any }
func (y *YiginAny) Ekle(o any) { y.ogeler = append(y.ogeler, o) }
func (y *YiginAny) Tepe() any { return y.ogeler[len(y.ogeler)-1] }
func F() {
	var y YiginAny
	y.Ekle(3)
	t, tamam := y.Tepe().(int)
	_ = tamam
	_ = t + 1
}`

	genelIleIddiasiz := `package sinama
type Yigin[T any] struct{ ogeler []T }
func (y *Yigin[T]) Ekle(o T) { y.ogeler = append(y.ogeler, o) }
func (y *Yigin[T]) Tepe() T { return y.ogeler[len(y.ogeler)-1] }
func F() {
	var y Yigin[int]
	y.Ekle(3)
	t := y.Tepe()
	_ = t + 1
}`

	fmt.Printf("%-42s %s\n", "durum", "sonuc")
	fmt.Printf("%-42s %s\n", "Yigin[string] = Yigin[int] (yer degistirme)", siniflaKaynak(yerDegistirme))
	fmt.Printf("%-42s %s\n", "any yigininda 0 tip iddiasiyla aritmetik", siniflaKaynak(anySizIddia))
	fmt.Printf("%-42s %s\n", "any yigininda 1 tip iddiasiyla aritmetik", siniflaKaynak(anyIleIddia))
	fmt.Printf("%-42s %s\n", "genel yiginda 0 tip iddiasiyla aritmetik", siniflaKaynak(genelIleIddiasiz))
}
```

```
durum                                      sonuc
Yigin[string] = Yigin[int] (yer degistirme) derlenmedi
any yigininda 0 tip iddiasiyla aritmetik   derlenmedi
any yigininda 1 tip iddiasiyla aritmetik   derlendi
genel yiginda 0 tip iddiasiyla aritmetik   derlendi
```

**GN10.** İlk satır, iki örneklemenin birbirinin yerine geçememesini doğrudan gösteriyor:
`b = a` derlenmiyor, çünkü `Yigin[string]` ile `Yigin[int]` derleyici için `[4]int` ile
`[3]int` kadar ayrı iki tip. Bu, örneklemenin çağıranın bildiriminde durmasının doğrudan
sonucu — bildirimde yazılan tip, o değişkenin kalıcı kimliğinin bir parçası oluyor.

**GN11.** Son üç satır aynı işi iki yazımla karşılaştırıyor. Boş arayüzle yazılan
`YiginAny`, `Tepe()`ten `any` döndürüyor; bu değeri doğrudan `+1` ile toplamaya çalışmak
derlenmiyor, çünkü `any`nin somut tipi kaynakta bilinmiyor. Tek çıkış yolu bir **tip
iddiası** yazmak (`y.Tepe().(int)`) — Tip İddiası ve Tip Anahtarı dersinin ölçtüğü aynı
mekanizma, burada bir kapsayıcının her okuma noktasında tekrar tekrar yazılması gereken bir
yük olarak beliriyor. Genel `Yigin[int]` ise `Tepe()`ten doğrudan `int` döndürüyor ve
`+1` hiçbir tip iddiası yazılmadan derleniyor — tip güvenliğinin ölçülebilir karşılığı bu:
aynı işi yapmak için gereken tip iddiası sayısı `any` yazımında en az bir, genel yazımda
sıfır.

Bu fark kapsayıcı büyüdükçe katlanıyor. `YiginAny`nin her okuma noktası — `Tepe`, bir
`Alt` yöntemi eklense onun dönüşü, bir `Tumu` yöntemi eklense onun döndürdüğü dilimin her
elemanı — kendi tip iddiasını taşımak zorunda, çünkü kapsayıcı tip bilgisini `any`nin
arkasında saklıyor ve her okuyan taraf bu bilgiyi kendi başına geri kazanmalı. `Yigin[T]`de
ise tip bilgisi kapsayıcının kendi tipinin bir parçası; kaç yeni yöntem eklenirse eklensin,
hiçbiri bir tip iddiası yazmak zorunda kalmıyor, çünkü dönüş tipleri zaten `T` — derleme
zamanında bilinen, somut bir tip. Bir tip iddiasının kendisi de bedelsiz değil: yanlış
tipte bir değer eklenmişse (bir `any` kapsayıcıya bu, hiçbir derleme hatası vermeden
mümkün), iddia çalışma zamanında panikler ya da iki yanıtlı biçimde sessizce başarısız
olur — genel yazımda bu hata sınıfının kendisi hiç var olmuyor, çünkü yanlış tipte bir
eleman eklemek zaten derlemede reddediliyor.

## Sınırlayıcı Ölçüm: Karşılaştırılabilirlik Hem Yapıya Hem T'ye Bağlı

Tip güvenliği bedelsiz değil. Bir genel tipin `==` ile karşılaştırılıp
karşılaştırılamayacağı, yalnız tip parametresine değil, kapsayıcının **kendi alan
yapısına** da bağlı — ve bu iki etken bağımsız çalışıyor.

```go
// karsilastirma.go — genel tipin karsilastirilabilirligi hem kendi alan yapisina hem T'ye bagli
package main

import (
	"fmt"
	"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 siniflaKaynak(kaynak string) string {
	if derlenirMi(kaynak) {
		return "derlendi"
	}
	return "derlenmedi"
}

func main() {
	yiginDilimli := `package sinama
type Yigin[T any] struct{ ogeler []T }
func F() bool { var a, b Yigin[int]; return a == b }`

	kutuKarsilastirilabilirT := `package sinama
type Kutu[T any] struct{ Deger T }
func F() bool { var a, b Kutu[int]; return a == b }`

	kutuKarsilastirilamazT := `package sinama
type Kutu[T any] struct{ Deger T }
func F() bool { var a, b Kutu[[]string]; return a == b }`

	fmt.Printf("%-46s %s\n", "durum", "sonuc")
	fmt.Printf("%-46s %s\n", "Yigin[int] == Yigin[int] (dilim alanli)", siniflaKaynak(yiginDilimli))
	fmt.Printf("%-46s %s\n", "Kutu[int] == Kutu[int] (T dogrudan, T=int)", siniflaKaynak(kutuKarsilastirilabilirT))
	fmt.Printf("%-46s %s\n", "Kutu[[]string] == Kutu[[]string] (T=dilim)", siniflaKaynak(kutuKarsilastirilamazT))
}
```

```
durum                                          sonuc
Yigin[int] == Yigin[int] (dilim alanli)        derlenmedi
Kutu[int] == Kutu[int] (T dogrudan, T=int)     derlendi
Kutu[[]string] == Kutu[[]string] (T=dilim)     derlenmedi
```

**GN12.** Üç satır iki bağımsız etkeni ayırıyor. `Yigin[T]` hiçbir zaman karşılaştırılamaz
— `T` `int` olsa bile, çünkü `ogeler` bir **dilim** alanı ve Sözlükler ile Diziler ve
Dilimler derslerinin (M09/K01) ölçtüğü gibi dilimler `==` ile karşılaştırılamaz; bu
kısıtlama kapsayıcının kendi alan yapısından geliyor, tip parametresinden değil. `Kutu[T]`
farklı bir yapı kurar — `Deger` alanı `T`yi doğrudan tutuyor, dilim değil — ve bu durumda
karşılaştırılabilirlik tamamen `T`ye devrediliyor: `Kutu[int]` karşılaştırılabiliyor çünkü
`int` karşılaştırılabilir, `Kutu[[]string]` karşılaştırılamıyor çünkü bu kez `T`nin
kendisi (`[]string`) karşılaştırılamaz bir tip. Genel bir tipin karşılaştırılabilirliği bu
yüzden tek bir soruya indirgenemez; hem kapsayıcının kendi tasarımına hem doldurulan `T`ye
bakmak gerekiyor.

Bu, kısıtların neden yeterli olmadığını da gösteriyor: `Yigin[T any]` kısıtını
`Yigin[T comparable]` yapmak `Kutu` için işe yarasa da `Yigin` için hiçbir şeyi değiştirmez
— `T` ne kadar karşılaştırılabilir olursa olsun, `ogeler` bir dilim olduğu sürece `Yigin`
karşılaştırılamaz kalır. Tip kısıtı yalnız `T`yi sınırlar, `T`yi taşıyan yapının kendi alan
düzenini değil.

Bu ayrımın somut bir karşılığı var: Sözlükler dersi (M09/K01) bir sözlüğün anahtar tipinin
karşılaştırılabilir olmak zorunda olduğunu ölçmüştü. `Yigin[int]` hiçbir zaman bir sözlük
anahtarı olamaz — `T` ne olursa olsun, çünkü karşılaştırılamazlık `ogeler` alanından
geliyor ve bu alan her örneklemede aynen duruyor. `Kutu[int]` ise anahtar olabilir, çünkü
`Deger` alanı `int`i doğrudan tutuyor ve `int` karşılaştırılabilir; `Kutu[[]string]` yine
olamaz, çünkü bu kez taşınan `T`nin kendisi karşılaştırılamaz. Aynı iki kapsayıcı kalıbı,
"bu tip bir sözlük anahtarı olabilir mi" sorusuna kaynaktaki alan yapısına bakılarak
önceden yanıt veriyor — çalışma zamanında bir anahtar denemesi yapmaya gerek kalmadan.

Üç ders boyunca genellik hep kaynağın içinde kaldı: tip parametresi ya çıkarıldı ya
açıkça yazıldı, ama her iki durumda da kaynağı okuyan biri, doğru yere baktığında, hangi
somut tipin kullanıldığını görebildi. Bu, Arayüz Kavramı dersinin ölçtüğü örtük
gerçekleştirimin tam tersi bir tavır: orada bir tipin bir arayüzü karşıladığı hiçbir
yerde yazmıyordu, burada bir kapsayıcının hangi tiple çalıştığı ya çağrının argümanından
ya da bildirimin köşeli parantezinden **her zaman** okunabiliyor. `Yigin[int]`in dinamik
tipi `%T`ye sorulmadan da bilinebiliyor, çünkü kaynağın kendisinde yazılı; bir arayüz
değerinin dinamik tipi ise yalnız değere sorularak öğrenilebiliyordu. Kursun kapanış
dersi bu iki tavrı — hep okunabilir olan ile yalnız değere sorularak öğrenilebilen — aynı
işi yaparak karşılaştırır.

Bu okunabilirlik bedelsiz değil: `Yigin[int]`i okuyan biri `T`nin `int` olduğunu satırın
kendisinden öğreniyor, ama bu bilgi başka bir yerde — Genel Fonksiyonlar dersindeki gibi
bir argümandan — çıkarılamıyor; yazan tarafın onu yazmayı unutması mümkün değil, çünkü
sözdizimi bunu zorunlu kılıyor. Genelliğin kazandırdığı öngörülebilirlik, çağıranın
üstlendiği bu küçük bir yazım yüküyle geliyor.

## Özet

- Bir genel veri yapısının tip parametresi, genel fonksiyonun aksine, çağıranın kendi
  bildiriminde açıkça yazılır — çıkarılmaz.
- `Yigin[int]` ile `Yigin[string]`, aynı kaynaktan üretilmiş olsalar bile, çalışma
  zamanında `%T` ile okunan iki ayrı dinamik tiptir ve biri diğerinin yerine geçemez.
- Tip güvenliğinin ölçülebilir karşılığı: aynı işi boş arayüzle yazmak en az bir tip
  iddiası gerektiriyor, genel yazımda bu sayı sıfır.
- Bir genel tipin karşılaştırılabilirliği iki bağımsız etkene bağlıdır: kapsayıcının kendi
  alan yapısı (dilim alanı taşıyorsa hiçbir zaman karşılaştırılamaz) ve — kapsayıcı `T`yi
  doğrudan tutuyorsa — `T`nin kendi karşılaştırılabilirliği.
- Bir tip kısıtı yalnız tip parametresini sınırlar; kapsayıcının kendi alan düzeninden
  gelen sınırları değiştiremez.

## Sonraki Adım

Üç ders boyunca genellik hep tek bir tarafta ölçüldü: bağ ya bildirimde ya kullanım
yerinde kuruldu, hiçbir zaman değere girmedi. Arayüz konusu ise tam tersini ölçmüştü —
tip bilgisi değerin içinde taşınıyordu ve ancak değere sorularak okunabiliyordu. Kursun
son dersi bu iki yazımı, ve aralarında duran arayüz sözleşmesini, aynı işi üç kez yaparak
yan yana koyar: hangi yazım kaç tip iddiası gerektiriyor, hangisi derleme zamanında
durup hangisi çalışma zamanına kalıyor, ve genellik her zaman kazanıyor mu.
