Marshal ve Unmarshal
json.Marshal bir Go değerini JSON baytlarına çevirir. json.Unmarshal bir Go değerini JSON baytlarından doldurur. Struct tag'leri JSON alan adlarını seçer.
Email ilk çıktıda omitempty ve boş bir string nedeniyle eksik. Unmarshal bir pointer ister (&back); değerin kendisini aktarmak bir InvalidUnmarshalError döndürür.
Struct tag'leri
Tag söz dizimi json:"name,option,option" şeklindedir.
| Tag | Etkisi |
|---|---|
json:"user_id" | anahtar olarak user_id kullan |
json:"email,omitempty" | false, 0, "", nil ya da boş bir slice veya map olduğunda çıkar |
json:",omitzero" (Go 1.24) | değer sıfır değeri olduğunda ya da IsZero() true döndürdüğünde çıkar |
json:"-" | bu alanı asla kodlama ya da çözme |
json:"-," | düz - anahtarını kullan |
json:"count,string" | bir sayıyı ya da bool'u bir JSON string'i olarak kodla ("42") |
| tag yok | anahtar Go alan adıdır, UserID |
Parola struct'tan hiç çıkmaz, bakiye tırnak içine alınır ve deleted_at kaybolurken created_at sıfır zamanı 0001-01-01T00:00:00Z yazdırır. omitzero'nun eklenmesinin nedeni bu farktır: omitempty struct'lar için hiç çalışmadı ve time.Time ile uzun süredir bilinen bir sürprizdir. Go 1.23 ve öncesinde aynı etkiyi elde etmek için omitempty ile bir *time.Time kullanın.
MarshalIndent(v, prefix, indent) okunabilir çıktı üretir. Onu yapılandırma dosyaları ve hata ayıklama için kullanın; API'ler genellikle sıkıştırılmış JSON gönderir.
Yalnızca dışa açık alanlar
encoding/json reflection kullanır ve yalnızca dışa açık alanları görebilir. Go'daki en yaygın JSON hatası budur:
type point struct {
x, y int // lowercase: json.Marshal(point{1, 2}) gives {}
}
Hata yok, uyarı yok; çıkışta yalnızca {}, girişte sıfırda bırakılan alanlar. Alanları büyük harfle başlatın ve küçük harfli anahtarlar için tag ekleyin.
Çözme alanları nasıl eşleştirir
Bir struct'a unmarshal ederken:
- Anahtarlar tag adıyla ya da alan adıyla büyük/küçük harf duyarsız eşleştirilir.
{"NAME": "x"},json:"name"tag'li bir alanı doldurur. - Eşleşen alanı olmayan anahtarlar sessizce yok sayılır.
- Eşleşen anahtarı olmayan alanlar mevcut değerlerini korur. Unmarshal onları sıfırlamaz, bu yüzden zaten verisi olan bir struct'a çözmek onunla birleştirir.
- Bir tip uyuşmazlığı (struct'ta
intolan yerde bir string) bir*json.UnmarshalTypeErrordöndürür, ama diğer alanlar yine doldurulur.
Beklenmeyen anahtarları reddetmek için, örneğin katı bir API'de ya da yazım hatalı bir yapılandırma dosyasında, DisallowUnknownFields ile bir Decoder kullanın:
Bilinmeyen yapı: map[string]any
Biçimi önceden bilmediğinizde map[string]any'ye ya da any'ye çözün. Eşleme sabittir:
| JSON | Go |
|---|---|
| nesne | map[string]any |
| dizi | []any |
| string | string |
| sayı | float64 |
| true / false | bool |
| null | nil |
Çıktıda iki tuzak görünüyor. Her sayı float64'tür, bu yüzden m["stock"].(int) başarısız olurdu. Ve 2^53'ün üzerindeki tam sayılar float64 olarak hassasiyet kaybeder: 9007199254740993 id'si ...992 olarak geri gelir. UseNumber ikisinden de kaçınır.
Yapının bir kısmını biliyorsanız o kısmı bir struct'a çözün ve geri kalanı için json.RawMessage kullanın. Bir alanın ham baytlarını tutar, böylece tipini öğrendiğinizde onu daha sonra çözebilirsiniz.
Slice'lar, map'ler, pointer'lar ve nil
| Go değeri | JSON |
|---|---|
nil slice (var s []int) | null |
boş slice ([]int{}) | [] |
nil map | null |
nil pointer | null |
[]byte | bir base64 string'i |
map[string]T | anahtarları sıralı bir nesne |
map[int]T | tam sayı anahtarları string olan bir nesne |
nil ile boş slice arasındaki fark bir dizi bekleyen API istemcileri için önemlidir. Alanın [] olması gerektiğinde []T{} ya da make([]T, 0) ile başlatın.
Girdide "yok" ile "sıfır"ı ayırt etmeniz gerektiğinde bir pointer alan (*int, *bool) kullanın. Unmarshal'dan sonra nil bir pointer anahtarın eksik ya da null olduğu anlamına gelir; 0'a işaret eden bir pointer ise istemcinin 0 gönderdiği anlamına gelir.
Akışlar: Encoder ve Decoder
json.Marshal ve Unmarshal bütün byte slice'ları üzerinde çalışır. Bir io.Reader ya da io.Writer için (bir HTTP gövdesi, bir dosya, stdin) json.NewDecoder ve json.NewEncoder kullanın. Bir Decoder ayrıca bir JSON değerleri dizisini tek tek okuyabilir:
Encoder.Encode her değerden sonra bir yeni satır yazar. Varsayılan olarak hem Marshal hem Encoder, JSON'un HTML'e gömülmesi güvenli olsun diye <, > ve & karakterlerini \u003c, \u003e ve \u0026 olarak kaçışlar. SetEscapeHTML(false) bunu kapatır. HTTP handler'larında olağan çift json.NewDecoder(r.Body).Decode(&v) ve json.NewEncoder(w).Encode(v)'dir.
Özel kodlama
Bir tip json.Marshaler ve json.Unmarshaler'ı gerçekleştirerek kendi JSON'unu kontrol edebilir. Yaygın bir durum, bir sayı olarak değil bir ad olarak görünmesi gereken bir iota enum'udur:
MarshalJSON'un hem değerler hem de pointer'lar için çalışsın diye değer alıcısı vardır; UnmarshalJSON değeri değiştirdiği için pointer alıcıya ihtiyaç duyar. Yalnızca bir string biçimine ihtiyaç duyan tipler bunun yerine encoding.TextMarshaler'ı (MarshalText) gerçekleştirebilir; bu da onları map anahtarı olarak da kullanılabilir yapar.
Sık yapılan hatalar
- Küçük harfli alan adları. Sessizce atlanırlar.
Unmarshal'a bir değer aktarmak. Bir pointer ister.- Hatayı yok saymak. Hatalı biçimli JSON ve tip uyuşmazlıkları yalnızca onun üzerinden bildirilir.
map[string]anyiçindeki sayılarınintolduğunu varsaymak. Onlarfloat64'tür.omitempty'nin boş bir struct'ı ya da sıfır birtime.Time'ı atmasını beklemek. Go 1.24'teomitzeroya da bir pointer kullanın.- Map'lerde alan sırasına güvenmek. Map anahtarları çıktıda sıralanır; struct alanları tanım sıralarını korur.
Sıkça Sorulan Sorular
Go'da bir struct JSON'a nasıl dönüştürülür?
[]byte ve bir hata döndüren json.Marshal(v)'yi çağırın. Yalnızca dışa açık alanlar (büyük harfle başlayan adlar) dahil edilir. Bir alanın JSON anahtarını belirlemek için json:"name" gibi bir struct tag'i kullanın. Girintili çıktı için json.MarshalIndent(v, "", " ") kullanın.
Struct alanlarım JSON çıktısında neden eksik?
encoding/json yalnızca dışa açık alanları görür. name (küçük harf) adlı bir alan hem marshal hem de unmarshal sırasında ona görünmez. Alanı büyük harfle başlatın ve JSON anahtarını json:"name" gibi bir tag ile ayarlayın.
Go JSON'da omitempty ne yapar?
omitempty, bir alan boş bir değer tuttuğunda onu çıktıdan çıkarır: false, 0, "", nil bir pointer ya da interface, veya boş bir slice ya da map. Bir struct'ı ya da time.Time'ı boş saymaz. Go 1.24, struct'lar ve time.Time dahil kendi tipinin sıfır değeri olan (ya da IsZero() metodu true döndüren) her değeri çıkaran omitzero'yu ekledi.
Go'da yapısı bilinmeyen JSON nasıl ayrıştırılır?
map[string]any'ye (ya da any'ye) unmarshal edin. Nesneler map[string]any, diziler []any, string'ler string, boolean'lar bool ve her sayı float64 olur. Değerleri okumak için type assertion'ları, büyük tam sayıların kesin kalması gerekiyorsa Decoder.UseNumber'ı kullanın.