---
title: 'Tip Kısıtları'
source: 'https://academia.sh/tr/kurslar/go-tip-sistemi/tip-kisitlari'
course: 'Arayüzler, Hatalar ve Genellikler'
language: tr
updated: '2026-08-23T14:25:02+00:00'
license: 'CC BY-SA 4.0'
---

# Tip Kısıtları

Bir tip kısıtı da bir arayüzdür, ama yöntem değil tip kümesi listeler: aynı üç kısıt dört adayla sınandığında SadeceInt yalnız int'i, ~int içeren TemelTipiInt de temeli int olan adlandırılmış tipleri, ~int|~float64 birleşimi Sayisal da ikisini birden kabul ediyor — 1/4, 2/4, 3/4. Sınırlayıcı ölçüm, tip kümesi listeleyen bir arayüzün sıradan bir değer tipi olarak kullanılamadığını, yalnız yöntem listeleyen bir arayüzün hem kısıt hem değer tipi olabildiğini gösteriyor.

Genel Fonksiyonlar dersi kısıtsız bir tip parametresinin gövdede neredeyse işe yaramaz
olduğunu ölçtü: `any` ile `==` de `+` de derlenmiyordu, yalnız dilimin kendi yapısına
bakan `len` gibi işlemler geçiyordu. O ders bu boşluğu dolduran mekanizmayı bir cümleyle
açık bırakmıştı: bir tip kısıtı, tip parametresinin kabul ettiği tiplerin kümesini ve o
kümenin garanti ettiği işlemleri kaynakta **açıkça** yazan bir arayüzdür. Bu ders o
cümleyi açıyor ve aynı soruyu tekrar soruyor: bu kısıt kaynakta nerede duruyor, ve neyi
kabul ettiğini nereden biliyoruz?

Yanıt kısa: kısıt **bildirimde** durur. Ortak ölçümde "tip kısıtının bildirimi" dört
bildirim örneğinden biridir — gömme, derleme zamanı uyum kanıtı ve genel tipin
örneklenmesiyle birlikte, kaynakta açıkça yazılan dört bağdan biri. Bu ders o bağın
nasıl yazıldığını ve neyi sınırladığını ölçer: bir kısıt hangi tipleri kabul ediyor, bu
kabulü genişletmenin bir bedeli var mı, ve kısıt arayüzünün kendisi başka nerelerde
kullanılabiliyor.

## Kısıt Bir Tip Kümesi Listeler

**GN5.** Sıradan bir arayüz bir **yöntem kümesi** listeler: `interface{ Yaz() string }`
diyen bir tip, `Yaz` adlı bir yöntemi olan her tipi kabul eder. Bir tip kısıtı da
sözdizimsel olarak bir arayüzdür — `interface{ ... }` yazılır — ama parantez içine yöntem
imzası yerine **tip adları** yazılabilir: `interface{ int | float64 }`, yalnız `int` ya da
yalnız `float64` olan tipleri kabul eden bir **tip kümesi** tanımlar. Bu, aynı sözdiziminin
iki ayrı işte kullanılması: biri "bu yöntemleri sağla" diyor, öbürü "bu tiplerden biri ol"
diyor.

`~` işareti bu kümeyi genişletir. `~int`, yalnız `int`in kendisini değil, **temel tipi**
`int` olan her adlandırılmış tipi de kapsar — `type Yas int` yazıldığında `Yas` artık
`~int`in kümesine girer, ama `int`in kümesine girmez, çünkü `Yas` ile `int` aynı tip
değildir, yalnız aynı temel tipi paylaşırlar. Aşağıdaki ölçüm üç kısıtı dört adayla
sınıyor: `int`in kendisi, temeli `int` olan adlandırılmış bir tip (`Yas`), `float64`, ve
hiçbirine uymayan `string`.

```go
// kisit.go — uc kisitin kac tipi kabul ettigi, derleyiciye sorularak sayiliyor
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
}

type kisitTanimi struct{ ad, govde string }
type tipTanimi struct{ ad, bildirim, deger string }

func main() {
	kisitlar := []kisitTanimi{
		{"SadeceInt", "interface{ int }"},
		{"TemelTipiInt", "interface{ ~int }"},
		{"Sayisal", "interface{ ~int | ~float64 }"},
	}
	tipler := []tipTanimi{
		{"int", "", "3"},
		{"Yas (temeli int)", "type Yas int\n", "Yas(3)"},
		{"float64", "", "3.5"},
		{"string", "", `"x"`},
	}

	fmt.Printf("%-16s", "kisit")
	for _, t := range tipler {
		fmt.Printf("%-20s", t.ad)
	}
	fmt.Println()

	for _, k := range kisitlar {
		fmt.Printf("%-16s", k.ad)
		kabul := 0
		for _, t := range tipler {
			kaynak := fmt.Sprintf("package sinama\n%stype K %s\nfunc F[T K](a T) {}\nfunc G() { F(%s) }",
				t.bildirim, k.govde, t.deger)
			ok := derlenirMi(kaynak)
			sonuc := "hayir"
			if ok {
				kabul++
				sonuc = "evet"
			}
			fmt.Printf("%-20s", sonuc)
		}
		fmt.Printf("%d/4\n", kabul)
	}
}
```

```
kisit           int                 Yas (temeli int)    float64             string              
SadeceInt       evet                hayir               hayir               hayir               1/4
TemelTipiInt    evet                evet                hayir               hayir               2/4
Sayisal         evet                evet                evet                hayir               3/4
```

**GN6.** Üç satır, aynı dört adayla sınandığında, kısıtın kaynaktaki yazımına göre üç ayrı
kabul sayısı üretiyor. `SadeceInt` yalnız `int`in kendisini kabul ediyor — `Yas`, temeli
`int` olsa bile ayrı bir tip olduğu için reddediliyor; bu, iki dizinin uzunluğu farklı
olduğunda ayrı tip sayılmasıyla aynı katılıktır (Diziler ve Dilimler dersi, M09/K01).
`TemelTipiInt` `~int` yazdığı için `Yas`ı da kabul ediyor ve kabul sayısı ikiye çıkıyor.
`Sayisal` iki `~` teriminin birleşimini (`|`) listelediği için hem tam sayı hem ondalık
tarafını kapsıyor ve üçe çıkıyor — `string` ise üçünde de reddediliyor, çünkü hiçbir terim
onu kapsamıyor. Kabul sayısındaki bu artış kaynaktan doğrudan okunabilir: `SadeceInt`in
gövdesinde bir terim var, `TemelTipiInt`inkinde bir terim ama tilde'li, `Sayisal`ınkinde
iki terim birleşimli. Kısıtın ne kadar geniş olduğu, kısıtın **kendi bildirimindeki** terim
sayısına ve tilde işaretine bakılarak, hiçbir çağrı yapılmadan önceden söylenebilir.

Bu ölçüm aynı zamanda bağın bozulduğunda nerede göründüğünü de gösteriyor: bir çağıran
kısıtın kümesinde olmayan bir tiple bir genel fonksiyonu örneklemeye çalıştığında, hata
çalışma zamanında değil **derlemede** çıkıyor — tablodaki her "hayir" bir derleme reddi,
`string` argümanıyla `SadeceInt` kısıtlı bir fonksiyonu çağırmaya çalışmanın bir panikle
değil bir derleme durmasıyla sonuçlanacağının kanıtı.

Kısıtın kendisi de örtük bir gerçekleştirim modeliyle çalışıyor: `Yas` tipi hiçbir yerde
"ben `TemelTipiInt`i karşılıyorum" demiyor, `type Yas int` satırı bile bir kısıttan hiç
söz etmiyor. Bir tipin bir kısıtın kümesine girip girmediği, o tipin kendi kaynağına değil
temel tipine bakılarak, dışarıdan belirleniyor — Arayüz Kavramı dersinin ölçtüğü örtük
gerçekleştirim modeliyle aynı düzenek, burada yöntemler yerine tip kimliği üzerinden
işliyor. Fark şurada: bir arayüzü örtük karşılamak için bir tipin belirli yöntemleri
**yazması** gerekiyor, bir kısıtı örtük karşılamak için ise bir tipin hiçbir şey
yazmasına gerek yok — yalnız temel tipinin kısıtın listelediği terimlerden birine uyması
yeterli. `Yas` tipini tanımlayan satır, kısıt tanımlanmadan önce de yazılmış olabilirdi;
kısıt sonradan geldiğinde `Yas` otomatik olarak onun kümesine girdi, çünkü üyelik
`Yas`ın kaynağına değil temel tipine bakıyor.

`|` işaretiyle ayrılan terimlerin oluşturduğu bu yapıya **küme birleşimi** denir — kısıtın
kabul ettiği tip kümesi, her terimin kendi kümesinin birleşimidir. `Sayisal`ın kümesi
`~int`in kümesiyle `~float64`ün kümesinin birleşimi; bir tip bu iki alt kümeden **birine**
girerse yeterli, ikisine birden girmesi gerekmiyor. Küme birleşimi terimleri istenildiği
kadar çoğaltılabilir (`~int | ~int8 | ~int16 | ~int32 | ~int64`), ama her terim kümeyi
yalnız **genişletir**, hiçbir terim var olan bir üyeliği geri almaz — bu yüzden yukarıdaki
tablo tek yönlü bir artış gösteriyor, 1'den 2'ye, 2'den 3'e; hiçbir kısıt bir öncekinden
daha az tip kabul etmiyor.

Kısıt genişledikçe verdiği garanti daralıyor: `SadeceInt` yalnız bir tipi kabul ediyor ama
o tipin bütün `int` işlemlerini (bit kaydırma dâhil) garanti ediyor; `Sayisal` üç tipi daha
kabul ediyor ama yalnız her iki ailenin de ortak desteklediği işlemleri (`+`, `-`, `*`, `/`,
karşılaştırma işleçleri) garanti ediyor — bit kaydırma `float64` için tanımlı olmadığından
`Sayisal` kısıtlı bir gövdede yazılamaz. Kısıtın kaynaktaki genişliği ile gövdenin
yazabileceği işlemlerin darlığı ters orantılı; bu, Genel Fonksiyonlar dersinin `any`
kısıtıyla gösterdiği en uç durumun (hiçbir işlem yazılamaması) daha ölçülü bir hâli.

## `comparable`: Kısıt Boşluğunu Kapatan Yerleşik Kısıt

Genel Fonksiyonlar dersinin son ölçümü, kısıtsız `T` ile `a == b` yazan bir kaynağın
derlenmediğini göstermişti. Nedeni artık kaynaktan okunabilir: `any` hiçbir tip kümesi
terimi taşımıyor, yalnızca "her tip kabul edilir" diyor ve `==` işlecinin var olduğuna
dair hiçbir söz vermiyor. Dil bu boşluğu kendi yerleşik kısıtıyla kapatıyor:
`comparable`, `==` ve `!=` işleçlerini destekleyen her tipi kapsayan bir tip kümesi
tanımlar — dilim, sözlük ve fonksiyon tipleri hariç, çünkü bu üçü Go'da hiçbir zaman
`==` ile karşılaştırılamaz.

```go
// kapali.go — comparable kisiti gecen dersin kisitsiz == hatasini kapatiyor
package main

import "fmt"

func Esit[T comparable](a, b T) bool { return a == b }

func main() {
	fmt.Println("Esit(3, 3)     :", Esit(3, 3))
	fmt.Println("Esit(\"x\", \"y\") :", Esit("x", "y"))
}
```

```
Esit(3, 3)     : true
Esit("x", "y") : false
```

**GN7.** `Esit` burada, önceki dersin `Esit[T any]` yazımıyla aynı gövdeye sahip — tek fark
kısıtın adı. Bu tek sözcük, `==` işlecinin gövdede kullanılabilmesi için gereken bilgiyi
taşıyor; `comparable` `any` gibi standart kitaplığın bir parçası değil, dilin kendi
sözdiziminin bir üyesidir, tıpkı `any`nin kendisi gibi. Bağın nerede kurulduğu burada
iki katmanlı: kısıtın **hangi işlemlere izin verdiği** kısıtın kendi bildiriminde durur
(`comparable` mı `any` mi seçildi), ama o izin verilen işlemin **hangi somut tip için**
çalışacağı yine çağrı yerinde, örnekleme sırasında kurulur.

## Sınırlayıcı Ölçüm: Kısıt Arayüzü Yalnız Kısıt Konumunda Geçerli

Yukarıdaki üç kısıt da birer arayüz. Sıradan bir arayüz iki işte kullanılabilir: bir
değişkenin tipi olarak (`var x Yazici`) ve bir tip parametresinin kısıtı olarak
(`func F[T Yazici](...)`). Tip kümesi listeleyen bir kısıtın bu iki işten yalnız birini
yapabildiği, aşağıdaki ölçümün konusu.

```go
// sinirlayici.go — kisit arayuzu deger tipi olarak kullanilamiyor, derleyiciye sorularak olculuyor
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() {
	sayisalKisit := `package sinama
type Sayisal interface{ ~int | ~float64 }
func Topla[T Sayisal](a, b T) T { return a + b }`

	sayisalDeger := `package sinama
type Sayisal interface{ ~int | ~float64 }
func F() { var x Sayisal; _ = x }`

	yaziciKisit := `package sinama
type Yazici interface{ Yaz() string }
func F[T Yazici](a T) {}`

	yaziciDeger := `package sinama
type Yazici interface{ Yaz() string }
func F() { var x Yazici; _ = x }`

	fmt.Printf("%-38s %-12s %s\n", "arayuz", "kisit konumu", "deger tipi")
	fmt.Printf("%-38s %-12s %s\n", "Sayisal (tip kumesi listeler)",
		siniflaKaynak(sayisalKisit), siniflaKaynak(sayisalDeger))
	fmt.Printf("%-38s %-12s %s\n", "Yazici (yontem listeler)",
		siniflaKaynak(yaziciKisit), siniflaKaynak(yaziciDeger))
}
```

```
arayuz                                 kisit konumu deger tipi
Sayisal (tip kumesi listeler)          derlendi     derlenmedi
Yazici (yontem listeler)               derlendi     derlendi
```

**GN8.** `Sayisal`, bir kısıt konumunda (`[T Sayisal]`) derleniyor ama sıradan bir
değişken tipi olarak (`var x Sayisal`) derlenmiyor: tip kümesi terimi taşıyan bir arayüz,
kaynağın söylediği kadarıyla, yalnız kısıt olarak var olabilir. `Yazici` ise ikisinde de
derleniyor — yöntem listeleyen bir arayüzün tip kümesi kısıtlaması yok, bu yüzden hem bir
değeri taşıyabilir hem bir kısıt olabilir. Arayüzün iki işi burada ayrışıyor: **sözleşme**
(hangi yöntemler var) ve **kısıt** (hangi tipler geçerli) aynı sözdizimle yazılır, ama
tip kümesi terimi eklendiği an arayüz artık yalnız ikinci işi yapabiliyor.

Bu ayrım Arayüz Kavramı dersinin kurduğu modeli bozmuyor, ona bir sınır ekliyor: bir
arayüzün örtük gerçekleştirimi hâlâ geçerli, ama bir arayüzün **kendisinin** nerede
kullanılabileceği artık arayüzün gövdesindeki terimlere bağlı. `Sayisal` bir tipin ne
yapabileceğini söylemiyor, hangi tipler **olabileceğini** söylüyor — ve bu, bir yöntem
sözleşmesinden farklı bir sorudur. `Topla[T Sayisal]` fonksiyonu `T`nin `+` işlecini
desteklediğini biliyor, çünkü kısıtın tip kümesindeki her terim (`~int`, `~float64`) bu
işleci destekliyor; ama bu bilgi bir yöntem çağrısından değil, kümenin **üyeliğinden**
geliyor.

Bu derste iki yer yan yana kondu ve fark her ikisinde de koşturularak gösterildi: kısıtın
kendisi bildirimde durur (kaç terim, hangi tilde, hangi birleşim), ama kısıtın hangi somut
tipe uygulanacağı yine kullanım yerinde, örnekleme sırasında kurulur. Genel Fonksiyonlar
dersi bu ikinci yeri tek başına ölçmüştü; bu ders ona bildirim tarafını ekledi ve ikisinin
birlikte nasıl çalıştığını gösterdi — kısıt olmadan kullanım yeri hiçbir işleme izin
vermiyordu, kısıtla birlikte hangi işlemlerin izinli olduğu önceden, kaynaktan okunabilir
hâle geliyor.

Bu iki işin aynı sözdizimle yazılması, kısıt kavramının Go'ya sonradan eklenmiş ayrı bir
yapı olmamasının doğrudan sonucu: dil yeni bir anahtar sözcük açmak yerine mevcut arayüz
sözdizimini genişletti ve tip terimlerini de kabul eder hâle getirdi. Bunun bedeli
yukarıdaki ölçümde görüldü — genişleyen sözdizimin bir ucu (tip terimi eklemek) öbür ucu
(değer tipi olarak kullanmak) kapatıyor. Bir kısıt yazan kişi bu yüzden iki soruyu
birlikte düşünmek zorunda: kısıtın kabul edeceği tipler ne kadar geniş olmalı, ve bu
kısıtın bir gün sıradan bir değer tipi olarak da kullanılması gerekip gerekmeyeceği. İkinci
soru evetse, kısıt tip terimi taşımamalı — yalnız yöntem listelemeli; kısıt yalnız tip
parametrelerini sınırlamak için varsa, tip terimi eklemenin bir bedeli yok, çünkü zaten
başka bir işte kullanılması beklenmiyor.

## Özet

- Bir tip kısıtı sözdizimsel olarak bir arayüzdür, ama yöntem yerine bir **tip kümesi**
  listeler; hangi tiplerin kabul edildiği kısıtın kendi bildiriminden okunur.
- `~T` yalnız `T`nin kendisini değil, temel tipi `T` olan her adlandırılmış tipi de
  kapsar; `|` ile birleştirilen terimler kümeyi genişletir.
- Aynı dört aday üç kısıtla sınandığında kabul sayısı kısıttaki terim sayısına ve tilde
  işaretine göre artıyor: 1/4, 2/4, 3/4.
- Kısıt bozulduğunda — bir çağıran kümede olmayan bir tiple örnekleme yaptığında — bağ
  çalışma zamanında değil derlemede görünür.
- Tip kümesi terimi taşıyan bir arayüz yalnız kısıt konumunda geçerlidir; yöntem
  listeleyen bir arayüz hem kısıt hem sıradan değer tipi olabilir.
- Arayüzün iki işi — sözleşme ve kısıt — aynı sözdizimle yazılır, ama tip kümesi terimi
  eklendiği an arayüz yalnız ikinci işe daralır.

Kısıt, kısıtsız `any`nin çizdiği en dar sınırı genişletiyor, ama sınırı tamamen
kaldırmıyor: bir kısıt ne kadar geniş yazılırsa yazılsın, gövde yine yalnız kısıtın
garanti ettiği işlemleri kullanabilir. Bu, tip güvenliğinin bedelinin nereye gittiğini
gösteriyor — güvenlik, gövdenin yazabileceklerini kısıtın bildiriminde önceden
sınırlamaktan geliyor.

## Sonraki Adım

Kısıt, bir tip parametresinin kabul edildiği tipleri bildirimde sınırlıyor; ama kısıtın
kendisi, o tip parametresiyle kurulan bir **veri yapısının** nerede örnekleneceğini
söylemiyor. Sıradaki ders bunu ölçer: bir genel yapı `Yigin[int]` ve `Yigin[string]`
olarak iki kez örneklendiğinde, bu örneklemenin hangi tarafın bildiriminde — yapıyı yazan
tarafın mı, kullanan tarafın mı — durduğunu ve bu durmanın tip güvenliğine ne kazandırdığını.
