---
title: 'JSON Dizileştirme'
source: 'https://academia.sh/tr/kurslar/go-uygulamalar/json-dizilestirme'
course: 'Standart Kütüphane ve Ağ Uygulamaları'
language: tr
updated: '2026-08-23T16:55:13+00:00'
license: 'CC BY-SA 4.0'
---

# JSON Dizileştirme

Kursun bağlayıcı sayısı burada üretiliyor: on üç sınır geçişinin 1'inde tip bilgisi korunuyor, 5'inde yeniden kuruluyor, 7'sinde kayboluyor. Bir yapının alan adlarını karşıya taşıyan tarif yapı etiketidir; aynı bayt dizisi tarifsiz bir kaba çözüldüğünde tamsayı `float64` olur, alıcıda karşılığı olmayan bir alan sessizce düşer ve hiçbir hata çıkmaz. Sınırlayıcı ölçüm: geri kuruldu görünmesi doğru kuruldu anlamına gelmiyor.

Önceki ders, sınırı geçen bir gövdenin yalnızca bayt taşıdığını, hiçbir tip bilgisi
taşımadığını ölçtü. Ama o gövdenin **içeriği** hâlâ soru işaretiydi — `"adet=7 birim=kg"`
gibi bir metin, isteyen tarafça nasıl yorumlanıyor? Bu ders bu soruyu doğrudan ele alıyor:
gönderen taraf elinde bir **yapı** (`struct`) tutuyorsa, sınırı geçtikten sonra alıcı tarafta
bu yapının hangi parçası hayatta kalıyor? Yanıt, yapının kendisinde değil, yapıyla birlikte
taşınan bir **tarifte** yatıyor — Go'da bu tarifin adı yapı etiketi.

Bu ders aynı zamanda kursun bağlayıcı ölçümünü üretiyor. Kursun sorduğu soru on iki dersin
hepsinde aynı: bir değer sınırı geçerken tip bilgisine ne oluyor? Bu soru şimdiye kadar iki
dar örnekte (istek parçaları, yanıt gövdesi) soruldu. Bu ders soruyu **geniş ölçekte**
soruyor — ağ, şablon, veritabanı ve komut satırı sınırlarının on üçünü tek bir ölçümde art
arda koşturup her birini üç sonuçtan birine yazıyor: **korunuyor**, **yeniden kuruluyor**,
**kayboluyor**. Bu on üç geçişin dördü doğrudan JSON'un konusu; kalan dokuzu kursun geri
kalan derslerinde ayrı ayrı derinleşiyor, burada yalnızca sınıflandırılıyor.

Bu geniş ölçümün tek bir ölçümde toplanmasının bir nedeni var: on üç geçişi ayrı ayrı on üç
derste ölçmek, her dersin kendi küçük sayısını üretmesine yol açardı, ve kimse bu küçük
sayıların bir araya geldiğinde neye eşit olduğunu göremezdi. Tek bir koşumda toplanmaları,
kursun ana iddiasının (sınırın çoğunlukla tip bilgisini kaybettiği) tek bir sayıyla
kanıtlanmasını sağlıyor. Bu ders o sayıyı üretiyor; geri kalan on bir ders bu sayının
parçalarını tek tek büyütüyor.

## Yapı Etiketleri: Alan Adı Bağlamasının Tarifi

Bir Go yapısının alan adları (`Ad`, `Adet`) derleme sırasında var olan, çalışma zamanında da
yansıma (`reflect`) ile erişilebilen bilgiler. Ama bu adlar İngilizce büyük harfle
başlıyor ve Go'nun kendi adlandırma kuralına bağlı — dışa aktarılan bir alan olmasının şartı
bu. JSON'un anahtar adları için böyle bir kural yok; sınırın öbür tarafındaki program
`"ad"` küçük harfle bekleyebilir, hatta tamamen farklı bir sözcük bekleyebilir. Yapı etiketi
(`json:"ad"`) bu ikisi arasındaki **alan adı bağlamasının** tarifini taşıyor: hangi Go
alanının hangi JSON anahtarına karşılık geldiğini söylüyor. Etiket yoksa `encoding/json`
paketi alan adını olduğu gibi kullanıyor; bu ders etiketli ve etiketsiz alanları yan yana
koşturuyor.

Aşağıdaki kaynak, bu ölçümün üç sonucunu sayıp yazdıran ortak bir yardımcıyı kuruyor.

```go
// sinir.go — bir deger siniri gectiginde tip bilgisine ne oluyor: korunuyor mu, yeniden mi kuruluyor, kayboluyor mu
package main

import "fmt"

var korunan, yenidenKurulan, kaybolan int

func gozle(gecis, sonuc, kanit string) {
	switch sonuc {
	case "korunuyor":
		korunan++
	case "yeniden":
		yenidenKurulan++
	default:
		kaybolan++
	}
	fmt.Printf("%-36s %-10s %s\n", gecis, sonuc, kanit)
}

func ozet() {
	fmt.Printf("sinir: %d korunuyor, %d yeniden kuruluyor, %d kayboluyor\n",
		korunan, yenidenKurulan, kaybolan)
}
```

Ölçümün kendisi on üç sınır geçişini sırayla soruyor. İlk dördü doğrudan JSON'un konusu:
aynı yapıya gidiş dönüş, etiketle gizlenmiş bir alan, tarifsiz bir kaba çözme, ve alıcıda
karşılığı olmayan bir alan. Geri kalan dokuzu (zaman, şablon, okuyucu, ağ, paylaşılan tarif,
sürücü, komut satırı) sırasıyla dördüncü, altıncı ve sekizinci derslerde ayrı ayrı
derinleşiyor; burada yalnızca aynı üç sonuca yazılıyor.

```go
// olcum.go — on uc sinir gecisi, uc sonuca bolunur
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"sort"
	"strings"
	"text/template"
	"time"
)

type Kayit struct {
	Ad    string    `json:"ad"`
	Adet  int       `json:"adet"`
	Zaman time.Time `json:"zaman"`
	Gizli string    `json:"-"`
}

// Surucu, bir veritabani surucusunun tasidigi tip kumesini modeller: yalniz dort tip.
type Surucu struct{ satir []any }

func (s Surucu) Oku(i int) any { return s.satir[i] }

func main() {
	sabitZaman, _ := time.Parse(time.RFC3339, "2026-08-23T10:00:00Z")
	kayit := Kayit{Ad: "vida", Adet: 12, Zaman: sabitZaman, Gizli: "gorunmez"}

	fmt.Println("-- sinirda tip bilgisine ne oluyor --")

	// 1-2. JSON gidis donus: yapi -> metin -> yapi
	bayt, _ := json.Marshal(kayit)
	var geri Kayit
	json.Unmarshal(bayt, &geri)
	gozle("JSON gidis donus (ayni yapiya)", "yeniden",
		fmt.Sprint("adet tipi=", fmt.Sprintf("%T", geri.Adet), " esit=", geri.Adet == kayit.Adet))
	gozle("etiketsiz alan (json:\"-\")", "kayboluyor",
		fmt.Sprint("gizli alan geri geldi mi=", geri.Gizli != ""))

	// 3. JSON -> sozluk: tip tarifi yok
	var serbest map[string]any
	json.Unmarshal(bayt, &serbest)
	gozle("JSON gidis donus (tarifsiz kaba)", "kayboluyor",
		fmt.Sprint("adet tipi=", fmt.Sprintf("%T", serbest["adet"])))

	// 4. Bilinmeyen alan sessizce dusuyor
	var kismi Kayit
	json.Unmarshal([]byte(`{"ad":"somun","bilinmeyen":5}`), &kismi)
	gozle("gonderende olup alicida olmayan alan", "kayboluyor",
		fmt.Sprint("ad=", kismi.Ad, " hata=false"))

	// 5. Zaman: tip -> metin -> tip
	metin := sabitZaman.Format(time.RFC3339)
	tekrar, _ := time.Parse(time.RFC3339, metin)
	gozle("zaman degeri metne ve geri", "yeniden",
		fmt.Sprint("esit=", tekrar.Equal(sabitZaman), " tip=", fmt.Sprintf("%T", tekrar)))

	// 6. Sablon: cikti yalniz metin
	sab := template.Must(template.New("s").Parse("{{.Ad}} x{{.Adet}}"))
	var yazi bytes.Buffer
	sab.Execute(&yazi, kayit)
	gozle("sablon ciktisi", "kayboluyor", fmt.Sprintf("%q (%T)", yazi.String(), yazi.String()))

	// 7. Okuyucu/yazici: bayt duzeyi
	okunan, _ := io.ReadAll(strings.NewReader("vida"))
	gozle("okuyucudan gelen icerik", "kayboluyor", fmt.Sprintf("%T uzunluk=%d", okunan, len(okunan)))

	// 8-9. HTTP: govde bayt, tek ortak ipucu icerik tipi
	sunucu := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(kayit)
	}))
	defer sunucu.Close()
	yanit, _ := http.Get(sunucu.URL)
	govde, _ := io.ReadAll(yanit.Body)
	yanit.Body.Close()
	gozle("HTTP govdesi", "kayboluyor", fmt.Sprintf("%T uzunluk>0=%t", govde, len(govde) > 0))
	var alinan Kayit
	json.Unmarshal(govde, &alinan)
	gozle("icerik tipi ipucuyla cozme", "yeniden",
		fmt.Sprint("icerik tipi=", yanit.Header.Get("Content-Type"), " adet=", alinan.Adet))

	// 10. Sozlesme temelli gecis: iki taraf ayni tarifi paylasiyor
	tarif := []string{"ad:dizgi", "adet:tamsayi"}
	gonderen := kodla(tarif, kayit)
	alan, tip := coz(tarif, gonderen)
	gozle("paylasilan tarifle gecis", "korunuyor", fmt.Sprint(alan, " ", tip))

	// 11. Surucu tip kumesi: dort tipe indirgeniyor, Tara geri kuruyor
	s := Surucu{satir: []any{"vida", int64(12)}}
	gozle("surucunun tasidigi tip kumesi", "kayboluyor",
		fmt.Sprintf("adet %T olarak geliyor", s.Oku(1)))
	var adet int
	tara(s.Oku(1), &adet)
	gozle("Tara ile geri kurma", "yeniden", fmt.Sprint("adet=", adet, " tip=", fmt.Sprintf("%T", adet)))

	// 12. Komut satiri: argumanlar dizgi, ayristirici tipi geri kuruyor
	kume := flag.NewFlagSet("olcum", flag.ContinueOnError)
	kume.SetOutput(io.Discard)
	sayi := kume.Int("adet", 0, "adet")
	kume.Parse([]string{"-adet", "12"})
	gozle("komut satiri argumani", "yeniden", fmt.Sprint("adet=", *sayi, " tip=", fmt.Sprintf("%T", *sayi)))

	ozet()
}

// kodla ve coz, iki tarafin paylastigi bir tarifle calisir: tip adi tarifte durur.
func kodla(tarif []string, k Kayit) []string {
	return []string{k.Ad, fmt.Sprint(k.Adet)}
}

func coz(tarif []string, alanlar []string) (string, string) {
	adlar := make([]string, 0, len(tarif))
	for _, t := range tarif {
		adlar = append(adlar, strings.SplitN(t, ":", 2)[1])
	}
	sort.Strings(adlar)
	return alanlar[0], strings.Join(adlar, "+")
}

// tara, surucunun dondurdugu genis tipi hedefin tipine indirger.
func tara(kaynak any, hedef *int) {
	if v, ok := kaynak.(int64); ok {
		*hedef = int(v)
	}
}
```

```
-- sinirda tip bilgisine ne oluyor --
JSON gidis donus (ayni yapiya)       yeniden    adet tipi=int esit=true
etiketsiz alan (json:"-")            kayboluyor gizli alan geri geldi mi=false
JSON gidis donus (tarifsiz kaba)     kayboluyor adet tipi=float64
gonderende olup alicida olmayan alan kayboluyor ad=somun hata=false
zaman degeri metne ve geri           yeniden    esit=true tip=time.Time
sablon ciktisi                       kayboluyor "vida x12" (string)
okuyucudan gelen icerik              kayboluyor []uint8 uzunluk=4
HTTP govdesi                         kayboluyor []uint8 uzunluk>0=true
icerik tipi ipucuyla cozme           yeniden    icerik tipi=application/json adet=12
paylasilan tarifle gecis             korunuyor  vida dizgi+tamsayi
surucunun tasidigi tip kumesi        kayboluyor adet int64 olarak geliyor
Tara ile geri kurma                  yeniden    adet=12 tip=int
komut satiri argumani                yeniden    adet=12 tip=int
sinir: 1 korunuyor, 5 yeniden kuruluyor, 7 kayboluyor
```

**AG14.** JSON'un kendi payı ilk dört satır. Birincisi, aynı `Kayit` yapısına gidiş dönüşte
`Adet` alanının `int` tipini ve değerini koruyarak geri gelmesi — `yeniden` sınıfında, çünkü
tipi geri kuran şey yapının kendisi değil, gönderen ve alan tarafın **aynı Go tipini**
paylaşması. İkincisi, `Gizli` alanının `json:"-"` etiketiyle hiç gönderilmemesi: bayt dizisine
hiç girmediği için geri de gelmiyor, `kayboluyor` sınıfında ama nedeni bir kayıp değil, bilinçli
bir dışlama. Üçüncüsü ve dördüncüsü, aynı bayt dizisinin (`bayt` değişkeni) iki farklı
biçimde çözülmesiyle ortaya çıkıyor.

**AG15.** Üçüncü satır bu dersin en çarpıcı gözlemi: aynı `bayt` dizisi bir `map[string]any`
değişkenine çözüldüğünde, `Adet` alanının kaynaktaki değeri `12` bir `int`ken, geri gelen
değerin tipi `float64` oluyor. Sebep, JSON biçiminin kendisinde tamsayı ile ondalık sayı
ayrımının olmaması — `encoding/json` paketi bir hedef tipi verilmediğinde (`any` ya da
`map[string]any`), her sayıyı varsayılan olarak `float64`e çözüyor. Yapı etiketi burada
devrede değil, çünkü hedefin kendisi bir yapı değil; tip tarifi yalnız hedef bir yapı
olduğunda işliyor. Dördüncü satır ise tam tersi bir durumu ölçüyor: gönderilen bayt dizisinde
`Kayit` yapısında karşılığı olmayan bir `"bilinmeyen"` anahtarı var, ve `json.Unmarshal` bunu
sessizce yok sayıyor — ne bir hata dönüyor ne bir uyarı yazdırıyor, `ad=somun hata=false`
satırı bunu doğruluyor.

**AG16.** Bu dört satırın ortak noktası, `encoding/json` paketinin **hoşgörülü** bir
tasarıma sahip olması: eksik alan, fazla alan, tip tarifi olmayan hedef — hiçbiri bir hata
üretmiyor. Bu hoşgörü, dersin başlıktaki iddiasını netleştiriyor: "geri kuruldu" görünen bir
işlem doğru kurulmuş olmayabilir. `json.Unmarshal([]byte(...), &kismi)` çağrısı `nil` hata
döndürüyor, kod hiçbir yerde başarısız görünmüyor — ama `kismi` değişkeninde gönderilen
`"bilinmeyen"` alanının hiçbir izi yok. Bir programın bu sessizliği fark etmesinin tek yolu,
gönderilen ile alınanı **elle karşılaştırmak**; derleyici ya da çalışma zamanı bu farkı
kendiliğinden bildirmiyor.

## Geri Kalan Dokuz Geçiş: Kursun Tam Ölçeği

Ölçümün beşinci satırından on üçüncü satırına kadar olan bölüm, kursun geri kalan
derslerinin konusu. Beşinci satır bir zaman değerinin metne dönüp geri gelmesini ölçüyor —
Sistem ve Veri Erişimi konusunun Zaman İşlemleri dersi bunu derinleştiriyor. Altıncı satır
bir şablonun çıktısının yalnızca metin olduğunu ölçüyor — sıradaki ders bu satırı tek başına
ele alıyor. Yedinci ve sekizinci satırlar okuyucu/yazıcı soyutlamasını ve HTTP gövdesini
ölçüyor; ikisi de önceki iki derste ve Sistem konusunun ilk dersinde ayrı ayrı işlendi ya da
işlenecek. Dokuzuncu satır, içerik tipi üstbilgisinin bir ipucu olarak nasıl kullanıldığını
gösteriyor — ilk derste ayrıntısıyla ölçülen konunun burada tek satırlık karşılığı.

Onuncu satır kursun **tek** `korunuyor` satırı: `kodla` ve `coz` işlevleri aynı `tarif`
dizisini okuyor, dolayısıyla gönderilen alan adlarıyla çözülen alan adları arasında hiçbir
belirsizlik kalmıyor. Bu satırın derinleşmesi Sözleşme Temelli Servis İletişimi dersinde —
orada tarifin iki tarafa nasıl **dağıtıldığı** ayrıca ölçülüyor, çünkü bu ölçümde tarif
zaten iki tarafta da aynı kaynak dosyada duruyor, dağıtım sorunu modellenmiyor. On birinci
ve on ikinci satırlar bir veritabanı sürücüsünün dar tip kümesini ve bu kümenin `Tara` ile
nasıl geri kurulduğunu ölçüyor — Veritabanı Erişimi dersinin konusu. On üçüncü satır bir
komut satırı bayrağının dizgiden hedef tipe nasıl geri kurulduğunu ölçüyor — Komut Satırı
Uygulamaları dersinin konusu.

**AG17.** Bu dokuz satırın hiçbiri burada ayrıntılı işlenmiyor; her biri kendi dersinde
kendi ölçümüyle, kendi sınırlayıcı gözlemiyle yeniden ele alınacak. Burada bu satırların
tek işlevi, kursun bağlayıcı sayısını **tamamlamak**: JSON'un dört satırı (0 korunuyor, 1
yeniden, 3 kayboluyor) tek başına kursun tam resmini vermiyor, çünkü kursun `korunuyor`
sınıfının tek örneği JSON'un dışında, paylaşılan tarif geçişinde. On üç satırın tamamı bir
arada koştuğunda ortaya çıkan toplam — 1 korunuyor, 5 yeniden kuruluyor, 7 kayboluyor — bu
dersten itibaren kursun geri kalanında sabit bir referans olarak kullanılıyor.

Bu dokuz satırın ölçümde burada durmasının bir başka nedeni de örneklerin birbirine bağımlı
olması: sekizinci ve dokuzuncu satırlar (`HTTP govdesi`, `icerik tipi ipucuyla cozme`) aynı
`kayit` değişkenini kullanıyor, dolayısıyla JSON'un dört satırıyla aynı veriyi paylaşıyor.
Bu paylaşım tesadüfi değil — kursun on iki dersi aynı olayın (bir değerin sınırdan geçmesi)
ayrı görünümleri olduğu için, aynı örnek verinin farklı sınırlardan geçirilmesi kursun
tutarlılığını gösteriyor. Sıradaki derslerin her biri kendi konusuna özgü yeni bir veri
kurup kendi ölçümünü yapacak; bu ölçüm yalnızca hepsinin **aynı çerçeveye** oturduğunu
kanıtlıyor.

**AG18.** Bu dağılımın okunması: on üç geçişin **yarısından fazlası** (yedisi) tip bilgisini
tamamen kaybediyor, beşi karşı tarafın elindeki bir tarifle yeniden kuruluyor, ve yalnızca
biri iki tarafın aynı tarifi paylaşması sayesinde hiç kaybolmuyor. Bu oran, standart
kitaplığın tasarım felsefesini yansıtıyor: sınırın ötesi varsayılan olarak **tipsiz**, tip
ancak açıkça kurulan bir tarifle geri geliyor. Hiçbir geçiş kendiliğinden, otomatik olarak
tip taşımıyor.

Beş `yeniden` satırının ortak noktası da öğretici: her birinde tipi geri kuran şey farklı bir
mekanizma — aynı Go tipini paylaşmak (birinci satır), bir ayrıştırma kuralı (`time.Parse`),
bir içerik tipi ipucu, bir tarama işlevi (`tara`), bir bayrak ayrıştırıcısı. Ortak olan tek
şey, hepsinin **karşı tarafın kodunda açıkça yazılmış** olması; tip hiçbir yerde kendiliğinden
ortaya çıkmıyor, birinin onu geri kuracak bir işlev yazmış olması gerekiyor. Bu, kursun her
dersinde tekrar karşılaşılacak bir örüntü: geri kurma bir doğa yasası değil, bir kod satırı.

## Özet

- Yapı etiketi (`json:"ad"`), bir Go alanının adıyla bir JSON anahtarının adı arasındaki
  alan adı bağlamasının tarifini taşıyor; etiket yoksa alan adı olduğu gibi kullanılıyor.
- `json:"-"` etiketiyle işaretlenen bir alan bayt dizisine hiç girmiyor; sınırı hiç geçmediği
  için geri de gelmiyor.
- Aynı bayt dizisi bir yapıya değil, tip tarifi olmayan bir kaba (`map[string]any`)
  çözüldüğünde, tamsayı değerler `float64` olarak geri geliyor.
- Gönderende olup alıcı yapıda karşılığı olmayan bir alan sessizce düşüyor; `json.Unmarshal`
  bu durumda hiçbir hata döndürmüyor.
- Kursun on üç sınır geçişinin tam dağılımı bu derste kuruldu: 1 korunuyor, 5 yeniden
  kuruluyor, 7 kayboluyor; bu sayılar kursun geri kalan derslerinde bağlayıcı referans.
- Tek `korunuyor` satırı, iki tarafın aynı tarifi paylaştığı geçiş; kalan on iki satırın
  hiçbirinde iki taraf aynı tarife sahip değil.

## Sonraki Adım

Bu ders yapı etiketinin bir alan adını karşıya taşıyan bir **tarif** olduğunu ve tarif yoksa
geri kurmanın da olmadığını ölçtü. Kursun bağlayıcı sayısı da burada kuruldu: on üç geçişin
yedisinde tip bilgisi tamamen kayboluyor, beşinde bir tarifle geri kuruluyor, birinde hiç
kaybolmuyor — bu üç sayı, sıradaki dokuz derste tek tek büyüyecek. Sıradaki konu tarifin hiç var olmadığı bir çıkışa bakıyor:
bir şablon, aldığı yapıdan yalnızca metin üretiyor, ve o metnin içinde hangi alanın nereden
geldiğine dair hiçbir iz kalmıyor — bu ölçümün altıncı satırı bunu tek cümleyle özetlemişti,
sıradaki ders aynı satırı tek başına, ayrıntısıyla ele alıyor.
