---
title: 'Boş Arayüz ve `any`'
source: 'https://academia.sh/tr/kurslar/go-tip-sistemi/bos-arayuz-ve-any'
course: 'Arayüzler, Hatalar ve Genellikler'
language: tr
updated: '2026-08-23T14:25:02+00:00'
license: 'CC BY-SA 4.0'
---

# Boş Arayüz ve `any`

Boş arayüz sıfır yöntem istiyor, ve sıfır yöntemi her tip karşılıyor: kaynakta hangi tipin geleceği hiç yazılı değil, tip bilgisi değerin içinde taşınıyor. Aynı değer üç ayrı statik tiple taşındığında dinamik tip değişmiyor; bedeli, değere konan her şeyin çift hâline gelip doğrudan çağrılamaması. Sınırlayıcı ölçüm: nil bir işaretçi boş arayüze konduğunda arayüzün kendisi nil değil.

Önceki ders arayüz değerinin dinamik tipini bir kez okudu — `%T` ile `main.Dosya` — ve
üzerinde durmadı. Boş arayüz tam olarak bu satırın kendisi: hiçbir yöntem istemeyen bir
arayüz, kayıt sayısıyla değil sıfır sayısıyla tanımlanan bir arayüz. Kaynakta hangi tipin bu
arayüze konacağı hiç yazılı olmadığı için, konan tipin bilgisini birinin bir yerde taşıması
gerekiyor; önceki dersin bağlayıcı dağılımında o yerin adı zaten geçmişti — **değer**. Bu
ders o satırı büyütüyor.

Önceki dersteki `Yazar` ve `Kapatan` gibi arayüzler birer yöntem istiyordu; `Gomulu` ikisini
birden istiyordu. Boş arayüz bu sıralamanın öbür ucunda duruyor: hiç yöntem istemiyor. Bir
arayüzün ne kadar az istediği ile onu ne kadar çok tipin karşılayabildiği arasındaki ilişki
önceki derste sayıyla ölçülmüştü; bu ders o eğrinin sıfır noktasına odaklanıyor ve orada
neyin kazanılıp neyin kaybedildiğini ölçüyor.

## Sıfır Yöntem İsteyen Arayüz

Önceki derste yöntem sayısı bir, iki, üçe çıktıkça, aynı dört tipten onu karşılayabilenlerin
sayısı üç, iki, bire düşüyordu. Boş arayüz bu eğrinin sıfır ucu: `interface{}` hiç yöntem
istemiyor, ve hiçbir yöntemi olmayan bir koşulu her tip karşılıyor — boş bir küme her kümenin
alt kümesidir. Dilin kendi tip adı `any`, `interface{}`in kısaltması; bu ders arayüzün
kavramına **boş arayüz**, kod içindeki adına `any` diyor.

Boş arayüz hiçbir yöntem istemediği için hangi tipin ona konacağını kaynak hiç
sınırlamıyor: `var v any = 42`, `var v any = "metin"`, `var v any = Birim{}` üçü de
derleniyor, çünkü üçünün de karşılaması gereken sıfır yöntem var. Ama arayüzün sıfır yöntem
istemesi, konan değerin hiçbir bilgisinin kalmadığı anlamına gelmiyor. Tip bilgisi
kaybolmuyor, yalnız görünürlüğü değişiyor — kaynaktan okunabilen bir tip adı olmaktan çıkıp
çalışma zamanında sorulması gereken bir bilgiye dönüşüyor.

Bu ders boyunca yazılan her `fmt.Println` çağrısı da aslında aynı düzeneği kullanıyor:
standart kütüphanenin bu işlevi, parametrelerini `...any` olarak alıyor. Bir tam sayı, bir
dizgi ya da bir yapı — hangisi verilirse verilsin, çağrı sırasında her biri boş arayüze
konuyor ve `Println`in içinde `%T` benzeri bir sorgulamayla geri okunuyor. Boş arayüz bu
yüzden nadir görülen bir kenar durum değil; bu dersteki her çıktı satırı zaten ondan geçti.

## Aynı Değer, Üç Statik Tip

Bir değerin dinamik tipi, o değerin hangi statik tip üzerinden taşındığından bağımsız.
Aşağıdaki ölçüm aynı `Birim` değerini üç ayrı statik tipin arkasından geçiriyor — kendi
arayüzü, sonra boş arayüz, sonra doğrudan boş arayüz — ve her seferinde `%T` ile dinamik tipi
okuyor.

```go
// ayni-deger.go — ayni deger uc ayri statik tipte tasindiginda dinamik tip degismiyor
package main

import "fmt"

type Birim struct{ Ad string }

func (b Birim) Kimlik() string { return b.Ad }

type Tanimlayici interface{ Kimlik() string }

func main() {
	b := Birim{Ad: "birim-42"}

	var t1 Tanimlayici = b
	var t2 any = t1
	var t3 any = b

	fmt.Println("Tanimlayici olarak       :", fmt.Sprintf("%T", t1))
	fmt.Println("any'ye tasindiktan sonra :", fmt.Sprintf("%T", t2))
	fmt.Println("dogrudan any olarak      :", fmt.Sprintf("%T", t3))
}
```

```
Tanimlayici olarak       : main.Birim
any'ye tasindiktan sonra : main.Birim
dogrudan any olarak      : main.Birim
```

Üç değişken üç ayrı statik tip taşıyor — `Tanimlayici`, sonra `any`, sonra yine `any` ama
başka bir yoldan gelmiş — ve üçü de aynı yanıtı veriyor: `main.Birim`. `t1`den `t2`ye geçiş
bir dönüşüm değil, aynı çiftin (tip, değer) yeniden bir değişkene bağlanması; tip bilgisi
kaybolmuyor çünkü hiçbir noktada kaybedilecek bir şey olmuyor, arayüz değeri zaten en
baştan beri bu çifti taşıyordu. `Tanimlayici`nin tek yöntemi de, boş arayüzün sıfır
yöntemi de, aynı temel yapıyı görüntülüyor; yalnız görünen yöntem sayısı farklı.

**AR4.** `t3 := b` yerine `t3 any = b` yazılmasının nedeni, `Birim`in doğrudan boş arayüze
konduğu bir yolu da göstermek — `t1` ve `t2` zincirinin `Tanimlayici` üzerinden geçtiğini,
`t3`ün geçmediğini ayırt etmek için üçüncü bir satır bilinçli olarak eklendi.

## Aynı Kap, Dört Ayrı Dinamik Tip

Önceki ölçüm tek bir değeri üç ayrı statik tipten geçirdi ve dinamik tipin sabit kaldığını
gösterdi. Bu ölçüm tersini yapıyor: tek bir statik tip (`[]any`) içine dört ayrı dinamik tip
koyuyor ve her birinin kendi kimliğini koruduğunu gösteriyor.

```go
// karisik.go — ayni any dilimi ic ice farkli dinamik tipler tasiyor
package main

import "fmt"

type Birim struct{ Ad string }

func main() {
	degerler := []any{42, "metin", Birim{Ad: "x"}, 3.14}
	for _, d := range degerler {
		fmt.Printf("deger=%v dinamik tip=%T\n", d, d)
	}
	fmt.Println("dilimin statik tipi: []any, uzunluk:", len(degerler))
}
```

```
deger=42 dinamik tip=int
deger=metin dinamik tip=string
deger={x} dinamik tip=main.Birim
deger=3.14 dinamik tip=float64
dilimin statik tipi: []any, uzunluk: 4
```

**AR5.** Dizi bilinçli olarak dört ayrı temel kategoriden seçildi — bir tam sayı, bir dizgi,
bir yapı, bir kayan noktalı sayı — ki gösterim tek bir tip ailesine (örneğin yalnız sayısal
tipler) özgü bir davranış değil, boş arayüzün genel kuralı olduğu görülebilsin.

Dilimin kendisi tek bir statik tip taşıyor: `[]any`. Ama dört ögesi dört ayrı dinamik tip
taşıyor — `int`, `string`, `main.Birim`, `float64` — ve `range` döngüsü bunların hiçbirini
birbirine karıştırmıyor, her öge kendi çiftini kendisiyle birlikte getiriyor. Bu, önceki
ölçümün aynasıdır: orada aynı tip üç statik biçimde sabit kaldı, burada aynı statik biçim
dört ayrı tipi taşıyor. İkisi birlikte tip bilgisinin nerede durduğunu netleştiriyor — statik
tipte değil, her değerin kendi taşıdığı çiftte.

Bu tür heterojen bir kap — tek bir dilimde birbirinden farklı tipte değerler tutmak — tip
parametreleriyle yazılan genel veri yapılarından önce yalnız boş arayüzle kurulabiliyordu.
İki yazımın nerede ayrıştığı kursun genellikler bölümünde ölçülecek; burada yalnız boş
arayüzün bunu nasıl yaptığı önemli: her ögeyi kendi çiftiyle birlikte saklayarak.

## Bedel: Çift Olmak, Doğrudan Çağrılamamak

Tip bilgisinin değerde taşınmasının bir bedeli var: boş arayüze konan bir değer, kendi
yöntemleriyle **doğrudan** çağrılamıyor. `any` sıfır yöntem istediği için sıfır yöntem
sunuyor — üzerinde tanımlı hiçbir yöntem yok, konan değerin kendi yöntemleri olsa bile.
Çağırmak için önce tip iddiasıyla asıl tipe (ya da asıl tipin karşıladığı bir arayüze)
dönmek gerekiyor.

Bu, önceki dersteki küçük arayüz ölçümünün simetrik karşılığı. Orada yöntem sayısı arttıkça
onu karşılayan tip sayısı azalıyordu; burada yöntem sayısı sıfıra indiğinde erişim de
sıfırlanıyor. Boş arayüz her tipi kabul ediyor çünkü hiçbir şey istemiyor, ve hiçbir şey
istemediği için hiçbir şey de sunmuyor — kabul genişliği ile doğrudan erişim ters orantılı.
Derleyici burada bir tahmin yürütmüyor: `v`nin statik tipi `any` olduğu sürece, `v` üzerinde
hangi yöntemlerin bulunduğunu bilmesinin hiçbir yolu yok, çünkü bu bilgi ancak çalışma
zamanında değerin kendisine bakılarak öğrenilebilir.

```go
// arac.go — bir kaynak parcasinin derlenip derlenmedigini programin icinden sinar
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
}
```

Bu blok yalnız diske yazılıyor; iki kaynak parçasını üretip derleyiciyi çağıran asıl ölçüm
aşağıda.

```go
// bedel.go — any uzerinden dogrudan cagri reddediliyor, tip iddiasindan sonraki cagri gecerli
package main

import "fmt"

func main() {
	ortak := `package sinama

type Birim struct{ Ad string }

func (b Birim) Kimlik() string { return b.Ad }

type Tanimlayici interface{ Kimlik() string }

func F() string {
	var v any = Birim{Ad: "x"}
`
	dogrudanCagri := ortak + `	return v.Kimlik()
}
`
	iddiaylaCagri := ortak + `	return v.(Tanimlayici).Kimlik()
}
`
	fmt.Println("dogrudan cagri, any uzerinden  :", derlenirMi(dogrudanCagri))
	fmt.Println("tip iddiasiyla cagri           :", derlenirMi(iddiaylaCagri))
}
```

```
dogrudan cagri, any uzerinden  : false
tip iddiasiyla cagri           : true
```

`v.Kimlik()` derlenmiyor, çünkü `v`nin statik tipi `any` ve `any`nin yöntem kümesi boş;
derleyici `Kimlik` adlı bir yöntemi `any` üzerinde aramıyor bile, çünkü orada aranacak
hiçbir yöntem tanımlı değil. `v.(Tanimlayici).Kimlik()` derleniyor, çünkü tip iddiası önce
değeri `Tanimlayici`ye çeviriyor ve `Tanimlayici`nin (dolayısıyla `Kimlik`in) yöntem kümesi
üzerinden çağrı yapılabiliyor. Bedel şu: `any` bir değeri her tipten kabul ediyor, ama
karşılığında o değerin kendi davranışına doğrudan erişimi kapatıyor. Tip iddiasının kendisi
sıradaki dersin konusu; burada yalnız onun **gerekliliği** ölçülüyor.

Bu ret bir eksiklik değil, bilinçli bir sınır. Derleyici `v.Kimlik()` satırını görürken elinde
yalnız `v`nin statik tipi (`any`) var; hangi somut değerin orada duracağı derleme zamanında
henüz bilinmiyor, ilk çalıştığında belirleniyor. Derleyici bu boşluğu "muhtemelen `Kimlik`
vardır" diye tahmin ederek doldurmuyor — böyle bir tahmin, yanlış çıktığında ancak çalışma
zamanında, belki de üretim ortamında patlardı. Bunun yerine derleyici, statik tipin sunduğu
yöntem kümesinin dışına hiç çıkmıyor; boş arayüz için bu küme boş olduğundan, çağrı orada
duruyor. Tip iddiası bu boşluğu **açıkça** kapatan tek yol.

## Sınırlayıcı Ölçüm: Nil İşaretçi Taşıyan Arayüz Nil Değildir

Boş arayüzün en tuhaf satırı, tip bilgisinin bedelsiz taşınmadığını gösteriyor. Bir işaretçi
`nil` olabilir; aynı işaretçi boş arayüze konduğunda, arayüzün kendisi **nil olmuyor**.

```go
// nil-arayuz.go — isaretci nil olsa da onu tasiyan arayuz nil degil
package main

import "fmt"

type Sunucu struct{}

func main() {
	var s *Sunucu
	var v1 any = s
	var v2 any

	fmt.Println("isaretcinin kendisi nil mi  :", s == nil)
	fmt.Println("isaretciyi tasiyan v1 nil mi:", v1 == nil)
	fmt.Println("hic deger konmayan v2 nil mi:", v2 == nil)
}
```

```
isaretcinin kendisi nil mi  : true
isaretciyi tasiyan v1 nil mi: false
hic deger konmayan v2 nil mi: true
```

Üç satır bilinçli olarak yan yana konuldu. `s` gerçekten `nil` — hiçbir `Sunucu` örneğini
göstermiyor. `v1` bu `nil` işaretçiyi taşıyor, ama `v1 == nil` `false` veriyor: arayüz
değeri bir çift, ve bu çiftin tip yuvası dolu — `*main.Sunucu` orada duruyor — yalnız değer
yuvası `nil`. Çift yalnız **her iki yuvası da** boşken `nil` sayılıyor; `v2` hiç değer
almadığı için hem tip hem değer yuvası boş kalıyor ve gerçekten `nil`.

Çiftin tip yuvasının gerçekten ayrı bir bilgi taşıdığı, iki farklı işaretçi tipi yan yana
konduğunda daha da netleşiyor.

```go
// iki-nil.go — iki ayri isaretci tipinin nil degerleri birbirine esit sayilmiyor
package main

import "fmt"

type A struct{}
type B struct{}

func main() {
	var a *A
	var b *B
	var v1 any = a
	var v2 any = b

	fmt.Println("v1 nil mi       :", v1 == nil)
	fmt.Println("v2 nil mi       :", v2 == nil)
	fmt.Println("v1 v2'ye esit mi:", v1 == v2)
	fmt.Printf("v1 dinamik tip=%T, v2 dinamik tip=%T\n", v1, v2)
}
```

```
v1 nil mi       : false
v2 nil mi       : false
v1 v2'ye esit mi: false
v1 dinamik tip=*main.A, v2 dinamik tip=*main.B
```

`a` ve `b` ikisi de `nil` işaretçi ve ikisi de sıfır alanlı, görünüşte "boş" birer yapıyı
gösteriyor. Ama `v1` ile `v2` birbirine eşit değil, çünkü arayüz karşılaştırması önce tip
yuvasını karşılaştırıyor ve `*main.A` ile `*main.B` aynı tip değil. İki değer yuvası da
`nil` olsa bile, tip yuvaları farklı olduğu için çift olarak eşit sayılmıyorlar. Bu, tip
yuvasının değer yuvasından bağımsız, gerçek bir bilgi taşıdığının bir başka kanıtı — yalnız
"dolu mu boş mu" değil, "hangi tip" sorusunun da karşılaştırmaya girdiğini gösteriyor.

**AR6.** Bu, önceki dersin birinci iddiasının doğrudan sonucu: bağların sekizi değerin
içinde taşınıyorsa, değerin boş olması çiftin boş olması demek değil. Go Temelleri kursunun
Sıfır Değerler dersi `nil` dilime eklenebilirken `nil` sözlüğe yazılamadığını ölçmüştü; bu
satır aynı ailenin üçüncü örneği — `nil` sözcüğü aynı kalıyor, taşıdığı anlam tipten tipe
değişiyor.

Bu satırın pratik sonucu şu: bir fonksiyon `error` (kendisi bir arayüz) döndürüyorsa ve
içeride somut bir işaretçi tipi kullanıyorsa, o işaretçi `nil` olsa bile döndürülen hata
değeri `nil` **olmayabilir**. Çağıran taraf `hata == nil` diye sorduğunda `false` yanıtını
alır, çünkü sorduğu şey işaretçinin kendisi değil, onu taşıyan çifttir. Bu tuzağın tam
ölçümü hata değerlerine ayrılan derste yapılacak; burada yalnız kökeni gösterildi.

Kökeni bu kadar erken görmenin bir nedeni var: hata, kendisi de bir arayüz, ve arayüz olan
her şey aynı çift kuralına tabi. `error` boş arayüz değil — `Error() string` yöntemini
istiyor — ama boş arayüzle paylaştığı şey tam olarak bu ölçümün konusu: ikisi de bir tip
yuvası ve bir değer yuvası taşıyan bir çift. Boş arayüzde bu çifti doğrudan gözlemlemek
kolay, çünkü hiçbir yöntem araya girmiyor; hata arayüzünde aynı çift bir yöntem imzasının
arkasına gizleniyor ama davranışı değişmiyor.

## Özet

- Boş arayüz sıfır yöntem istiyor ve sıfır yöntemi her tip karşılıyor; `any` bu arayüzün
  kod içindeki adı.
- Aynı değer üç ayrı statik tiple (özel arayüz, ondan `any`ye, doğrudan `any`) taşındığında
  dinamik tip değişmiyor — tip bilgisi kaybolmuyor, yalnız görünürlüğü değişiyor.
- Boş arayüze konan bir değer doğrudan çağrılamıyor; `any`nin yöntem kümesi boş olduğu için
  çağrı önce bir tip iddiası gerektiriyor.
- Nil bir işaretçi boş arayüze konduğunda arayüzün kendisi nil değil — çift yalnız tip ve
  değer yuvası birlikte boşken nil sayılıyor.
- İki ayrı işaretçi tipinin `nil` değerleri boş arayüze konduğunda birbirine eşit sayılmıyor;
  karşılaştırma değer yuvasından önce tip yuvasına bakıyor.

## Sonraki Adım

Bu derste tip bilgisine yalnız `%T` ile, salt okuma amacıyla erişildi — hiçbir satır
`v`nin gerçek değerini geri almadı, yalnız hangi tipte olduğunu okudu. Ama bir programın asıl
sorması gereken soru genellikle "bu değerin tipi ne" değil, "bu değer şu tipi karşılıyor mu"
ve karşılıyorsa "asıl değeri bana ver". Boş arayüzden çıkışta zaten bir kez görüldü:
`v.(Tanimlayici)` değeri geri kazandırdı ama yanıtı denetlemeden. Sıradaki ders bu iki
soruyu ayrı ayrı ölçüyor: tip iddiasının iki yanıtlı biçimi ve tip anahtarının seçtiği dal,
değere sormanın iki ayrı yolu.
