encoding/json com Structs
Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy. Lição 76 de 107.
O pacote encoding/json permite converter structs do Go para JSON e vice-versa. Isso é essencial para APIs, arquivos de configuração e armazenamento de dados. As tags de struct controlam como os campos são mapeados para chaves JSON.
Para converter uma struct em JSON, use json.Marshal:
type User struct {
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
}
func main() {
user := User{Name: "Alice", Email: "alice@example.com", Age: 30}
data, _ := json.Marshal(user)
fmt.Println(string(data))
// {"name":"Alice","email":"alice@example.com","age":30}
}As tags de struct, como `json:"name"`, especificam os nomes das chaves JSON. Sem as tags, Go usa diretamente o nome do campo. Somente os campos exportados (com inicial maiúscula) são incluídos na saída JSON.
Para converter JSON de volta para uma struct, use json.Unmarshal:
jsonStr := `{"name":"Bob","email":"bob@example.com","age":25}`
var user User
json.Unmarshal([]byte(jsonStr), &user)
fmt.Println(user.Name) // BobOpções comuns de tags incluem omitempty para pular valores zero e - para ignorar um campo inteiramente:
type Product struct {
ID int `json:"id"`
Name string `json:"name"`
Price float64 `json:"price,omitempty"`
Internal string `json:"-"`
}Com omitempty, se Price for zero, ele não aparecerá no JSON. O campo Internal nunca é incluído, independentemente do seu valor.
Desafio
FácilVamos criar um sistema de catálogo de filmes que converte entre structs Go e JSON! Você praticará a serialização de structs para JSON e a desserialização de JSON de volta para structs, usando tags de structs para controlar os nomes dos campos JSON.
Você organizará seu código em dois arquivos:
movie.go: Defina seu modelo de dados de filme com as tags JSON apropriadas.Crie uma struct
Moviecom os seguintes campos e mapeamentos JSON:Title(string) mapeia para"title"Director(string) mapeia para"director"Year(int) mapeia para"year"Rating(float64) mapeia para"rating"comomitemptypara que filmes sem avaliação não exibam um campo de avaliaçãoInternalID(string) deve ser totalmente excluído do JSON usando"-"
Crie uma função
ToJSON(m Movie) stringque converta um Movie em uma string JSON. Crie tambémFromJSON(jsonStr string) Movieque analise uma string JSON e a converta novamente em uma struct Movie.main.go: Demonstre a conversão JSON em ambas as direções.Leia um tipo de operação (
encodeoudecode).Para
encode: Leia os detalhes do filme (título, diretor, ano, avaliação) em linhas separadas. Crie um Movie com um InternalID de"internal-123", converta-o para JSON e imprima o resultado.Para
decode: Leia uma string JSON, converta-a em uma struct Movie e imprima os detalhes do filme neste formato:Title: [title] Director: [director] Year: [year] Rating: [rating]Exiba a avaliação com uma casa decimal. Se a avaliação for 0 (não estiver presente no JSON), imprima
Rating: N/Aem vez disso.
As seguintes entradas serão fornecidas:
- Linha 1: Tipo de operação (
encodeoudecode) - Para encode: título, diretor, ano, avaliação (quatro linhas)
- Para decode: uma string JSON (uma linha)
Por exemplo, considerando:
encode
Inception
Christopher Nolan
2010
8.8Sua saída deverá ser:
{"title":"Inception","director":"Christopher Nolan","year":2010,"rating":8.8}Observe que InternalID não aparece na saída por causa da tag "-".
E considerando:
encode
The Matrix
Wachowskis
1999
0Sua saída deverá ser:
{"title":"The Matrix","director":"Wachowskis","year":1999}Observe que rating é omitido porque é zero e possui omitempty.
E considerando:
decode
{"title":"Interstellar","director":"Christopher Nolan","year":2014,"rating":8.6}Sua saída deverá ser:
Title: Interstellar
Director: Christopher Nolan
Year: 2014
Rating: 8.6E considerando:
decode
{"title":"Tenet","director":"Christopher Nolan","year":2020}Sua saída deverá ser:
Title: Tenet
Director: Christopher Nolan
Year: 2020
Rating: N/AExperimente você mesmo
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Ler o tipo de operação
operation, _ := reader.ReadString('\n')
operation = strings.TrimSpace(operation)
if operation == "encode" {
// Ler os detalhes do filme
title, _ := reader.ReadString('\n')
title = strings.TrimSpace(title)
director, _ := reader.ReadString('\n')
director = strings.TrimSpace(director)
yearStr, _ := reader.ReadString('\n')
yearStr = strings.TrimSpace(yearStr)
year, _ := strconv.Atoi(yearStr)
ratingStr, _ := reader.ReadString('\n')
ratingStr = strings.TrimSpace(ratingStr)
rating, _ := strconv.ParseFloat(ratingStr, 64)
// TODO: Criar uma struct Movie com os valores lidos
// Definir InternalID como "internal-123"
// Converter para JSON usando ToJSON e imprimir o resultado
} else if operation == "decode" {
// Ler a string JSON
jsonStr, _ := reader.ReadString('\n')
jsonStr = strings.TrimSpace(jsonStr)
// TODO: Converter JSON para Movie usando FromJSON
// Imprimir os detalhes do filme no formato exigido
// Usar fmt.Sprintf("%.1f", rating) para a formatação da avaliação
// Se rating for 0, imprimir "Rating: N/A" em vez disso
}
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP em Go
Arquivos ExternosWorkspace e Módulos do GoPacotes e ImportsNomes Exportados vs. Não ExportadosIntrodução à OOP em GoStructs como ClassesDefinindo Métodos em StructsReceptores de Ponteiro vs. de ValorInicialização de StructsFunções ConstrutorasRecapitulação — Calculadora Simples4Interfaces
Introdução às InterfacesImplementação ImplícitaInterface como ContratoInterface Vazia (any)Asserção de TipoSwitch de TipoComposição de InterfacesInterfaces Stringer e ErrorRecapitulação - Calculadora de Formas7Encapsulamento
Campos Exportados vs. Não ExportadosEncapsulamento no Nível de PacoteMétodos Getters e SettersOcultação de Informações em GoRecapitulação - Registros de Alunos10Genéricos (Go 1.18+)
Introdução aos genéricosParâmetros de tipoRestrições de tipoStructs genéricasAlternativa para métodos genéricosRecapitulação - Coleção genérica13Padrões de Projeto — Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão Abstract FactoryPadrão ObserverPadrão Strategy2Tipos e Structs em Profundidade
Tipos Básicos e CompostosDefinições de Tipos PersonalizadosTags de StructStructs AnônimasStructs AninhadasValores Zero e PadrõesRecapitulação - Livro de Contatos5Composição em vez de herança
Por que Go não tem herançaNoções básicas de incorporação de structsPromoção de métodosIncorporação de várias structsIncorporação vs agregaçãoOcultação de métodos incorporadosRecapitulação - Hierarquia de funcionários8Tratamento de Erros e OOP
A interface errorTipos de Erro PersonalizadosEncapsulamento de Erros (fmt.Errorf)Erros Sentinelaerrors.Is() e errors.As()Panic, Defer e RecoverRecapitulação - Analisador de Arquivos11Biblioteca Padrão e POO
io.Reader e io.Writersort.InterfaceInterface fmt.Stringerencoding/json com StructsInterface http.HandlerRevisão - Modelos de API REST3Ponteiros e Memória
Fundamentos de Ponteiros em GoPonteiros para StructsPassagem por Valor vs. ReferênciaA Função new()Coleta de Lixo em GoRecapitulação - Construtor de Lista Ligada6Polimorfismo em Go
Polimorfismo via InterfacesDuck Typing em GoRegras de Satisfação de InterfacesColeções PolimórficasInjeção de DependênciasRecapitulação - Processador de Pagamentos9Concorrência e OOP
Fundamentos de GoroutinesCanais e comunicaçãoCanais com e sem bufferInstrução selectsync.Mutex e sync.RWMutexsync.WaitGroupDesign de structs thread-safeRevisão - Worker PoolPratique por conta própria: Compilador de Go online