JSON'u json.Unmarshal ve json kullanarak çözme.


203

Ben istek üzerine bir JSON yük kodlamak ve yanıt bir JSON gövdeyi çözmek için gereken bir API istemcisi geliştiriyorum.

Birkaç kütüphaneden kaynak kodunu okudum ve gördüklerimden, temelde bir JSON dizesini kodlamak ve kodunu çözmek için iki olasılık var.

Kullan json.Unmarshalbütün yanıt dizesi geçirerek

data, err := ioutil.ReadAll(resp.Body)
if err == nil && data != nil {
    err = json.Unmarshal(data, value)
}

veya kullanarak json.NewDecoder.Decode

err = json.NewDecoder(resp.Body).Decode(value)

Benim durumumda, HTTP yanıtları ile uğraşırken io.Reader, ikinci sürüm daha az kod gerektirir gibi görünüyor, ancak her ikisini de gördüm beri ben diğeri yerine bir çözüm kullanmanız gerekir herhangi bir tercih olup olmadığını merak ediyorum.

Üstelik bu soruya gelen kabul cevap diyor

Lütfen json.Decoderyerine kullanın json.Unmarshal.

ama nedenini söylemiyordu. Gerçekten kullanmaktan kaçınmalı mıyım json.Unmarshal?


GitHub'daki bu çekme isteği, Unmarshal çağrısını json.NewDecoder ile değiştirerek "JSON kod çözme işlemindeki arabelleği kaldır" dedi.
Matt

Sadece hangi girdinin kullanmanız için daha uygun olduğuna bağlıdır. blog.golang.org/json-and-go her iki tekniği de kullanarak örnekler verir.
rexposadas

15
IMO, ioutil.ReadAllolduğu hemen hemen her zaman yapmak yanlış şey. Hedefinizle ilgili değildir, ancak son 20 TB yanıt JSON'unuzdaki sonuncudan sonra olsa bile, borudan gelenleri depolamak için yeterli bitişik belleğe sahip olmanızı gerektirir }.
Dustin

@Dustin Bunu io.LimitReaderönlemek için kullanabilirsiniz .
İnanç Gümüş

Yanıtlar:


240

Bu gerçekten girdinizin ne olduğuna bağlıdır. DecodeYöntemin uygulanmasına bakarsanız, json.Decoderbir Git değerine sabitlemeden önce bellekteki tüm JSON değerini arabelleğe alır. Bu nedenle çoğu durumda bellekte daha verimli olmayacaktır (dilin gelecekteki bir sürümünde bu kolayca değişebilir).

Yani daha iyi bir kural şudur:

  • Kullanım json.DecoderVerilerinizi geliyorsa io.Readerakışından veya veri akışından birden çok değer deşifre gerekir.
  • json.UnmarshalBellekte zaten JSON verisi varsa kullanın .

Bir HTTP isteğinden json.Decoderokuma durumunda, bir akıştan okuduğunuz için seçerim .


25
Ayrıca: Go 1.3 kaynak kodunu inceleyerek, kodlama için, bir json.Encoder kullanırsanız, tampon karmaşasını çok azaltacak küresel bir tampon havuzunu (yeni sync.Pool tarafından desteklenir) yeniden kullanacağını da öğrenebiliriz. çok fazla json kodluyorsanız. Json.Encoder'ın paylaştığı çok farklı küresel bir havuz var. Bunun json.Marshal arabirimi için yapılamamasının nedeni, baytların kullanıcıya döndürülmesi ve kullanıcının baytları havuza "geri döndürmenin" bir yolu olmamasıdır. Eğer kodlama çok yapıyorsanız, json.Marshal her zaman biraz tampon karmaşası vardır.
Aktau

@Flimzy: emin misin? Kaynak kodu kod çözmeden önce arabellekteki tüm değeri okuduğunu söylüyor: github.com/golang/go/blob/master/src/encoding/json/… . BufferedYöntem değerden sonra iç tampon içine okundu herhangi bir ekstra verileri görmek izin yoktur.
James Henstridge

@ JamesHenstridge: Hayır, muhtemelen haklısın. Ben sadece ifadenizi istediğinden farklı yorumluyordum. Karışıklık için özür dileriz.
Flimzy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.