Menu

Golang JSON: Marshal, Unmarshal ve Struct Tag'leri

Go'da encoding/json ile JSON kodlamak ve çözmek: Marshal ve Unmarshal, omitempty ve omitzero gibi struct tag'leri, okunabilir çıktı, map[string]any'ye çözmek, bilinmeyen alanları reddetmek ve Decoder ile akış.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

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.

TagEtkisi
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 yokanahtar 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 int olan yerde bir string) bir *json.UnmarshalTypeError dö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:

JSONGo
nesnemap[string]any
dizi[]any
stringstring
sayıfloat64
true / falsebool
nullnil

Çı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ğeriJSON
nil slice (var s []int)null
boş slice ([]int{})[]
nil mapnull
nil pointernull
[]bytebir base64 string'i
map[string]Tanahtarları sıralı bir nesne
map[int]Ttam 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]any içindeki sayıların int olduğunu varsaymak. Onlar float64'tür.
  • omitempty'nin boş bir struct'ı ya da sıfır bir time.Time'ı atmasını beklemek. Go 1.24'te omitzero ya 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.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA