Estou desenvolvendo um cliente de API em que preciso codificar uma carga JSON mediante solicitação e decodificar um corpo JSON da resposta.
Eu li o código fonte de várias bibliotecas e, pelo que vi, tenho basicamente duas possibilidades para codificar e decodificar uma string JSON.
Use json.Unmarshal
passar toda a cadeia de resposta
data, err := ioutil.ReadAll(resp.Body)
if err == nil && data != nil {
err = json.Unmarshal(data, value)
}
ou usando json.NewDecoder.Decode
err = json.NewDecoder(resp.Body).Decode(value)
No meu caso, ao lidar com respostas HTTP implementadas io.Reader
, a segunda versão parece exigir menos código, mas desde que eu vi as duas, fico imaginando se há alguma preferência se devo usar uma solução em vez da outra.
Além disso, a resposta aceita desta pergunta diz
Por favor use em
json.Decoder
vez dejson.Unmarshal
.
mas não mencionou o motivo. Devo realmente evitar o uso json.Unmarshal
?
ioutil.ReadAll
é quase sempre a coisa errada a fazer. Não está relacionado ao seu objetivo, mas exige que você tenha memória contígua suficiente para armazenar o que estiver vindo do canal, mesmo que os últimos 20 TB de resposta sejam os seguintes}
no JSON.io.LimitReader
para evitar isso.Respostas:
Realmente depende de qual é a sua entrada. Se você observar a implementação do
Decode
métodojson.Decoder
, ele armazena em buffer todo o valor JSON na memória antes de descompactá-lo para um valor Go. Portanto, na maioria dos casos, não será mais eficiente em termos de memória (embora isso possa mudar facilmente em uma versão futura do idioma).Portanto, uma melhor regra geral é esta:
json.Decoder
se seus dados vierem de umio.Reader
fluxo ou se você precisar decodificar vários valores a partir de um fluxo de dados.json.Unmarshal
se você já possui os dados JSON na memória.No caso de ler de uma solicitação HTTP, eu escolheria
json.Decoder
uma vez que você obviamente está lendo de um fluxo.fonte
Buffered
método existe para permitir que você veja quaisquer dados extras que foram lidos no buffer interno após o valor.