Menu
Coddy logo textTech

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 Go para JSON e vice-versa. Isso é essencial para APIs, arquivos de configuração e armazenamento de dados. Tags de struct controlam como os campos são mapeados para chaves JSON.

Para converter uma struct para 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, o Go usa o nome do campo diretamente. Apenas campos exportados (iniciados com letra 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)  // Bob

Opçõ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.

challenge icon

Desafio

Fácil

Vamos construir um sistema de catálogo de filmes que converte entre structs Go e JSON! Você praticará o marshaling de structs para JSON e o unmarshaling de JSON de volta para structs, usando struct tags 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 Movie com 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" com omitempty para que filmes sem avaliação não mostrem o campo de avaliação
    • InternalID (string) deve ser totalmente excluído do JSON usando "-"

    Crie uma função ToJSON(m Movie) string que converte um Movie para uma string JSON. Crie também FromJSON(jsonStr string) Movie que analisa uma string JSON de volta para uma struct Movie.

  • main.go: Demonstre a conversão JSON em ambas as direções.

    Leia um tipo de operação (encode ou decode).

    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 para 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 presente no JSON), imprima Rating: N/A em vez disso.

As seguintes entradas serão fornecidas:

  • Linha 1: Tipo de operação (encode ou decode)
  • Para encode: título, diretor, ano, avaliação (quatro linhas)
  • Para decode: uma string JSON (uma linha)

Por exemplo, dado:

encode
Inception
Christopher Nolan
2010
8.8

Sua saída deve 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 dado:

encode
The Matrix
Wachowskis
1999
0

Sua saída deve ser:

{"title":"The Matrix","director":"Wachowskis","year":1999}

Observe que rating é omitido porque é zero e possui omitempty.

E dado:

decode
{"title":"Interstellar","director":"Christopher Nolan","year":2014,"rating":8.6}

Sua saída deve ser:

Title: Interstellar
Director: Christopher Nolan
Year: 2014
Rating: 8.6

E dado:

decode
{"title":"Tenet","director":"Christopher Nolan","year":2020}

Sua saída deve ser:

Title: Tenet
Director: Christopher Nolan
Year: 2020
Rating: N/A

Folha de consulta

O pacote encoding/json converte structs Go para JSON e vice-versa usando json.Marshal e json.Unmarshal.

Para converter uma struct para JSON:

type User struct {
    Name  string `json:"name"`
    Email string `json:"email"`
    Age   int    `json:"age"`
}

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}

Para converter JSON de volta para uma struct:

jsonStr := `{"name":"Bob","email":"bob@example.com","age":25}`
var user User
json.Unmarshal([]byte(jsonStr), &user)
fmt.Println(user.Name)  // Bob

As tags de struct controlam o mapeamento de campos JSON:

  • `json:"name"` - mapeia o campo para a chave JSON "name"
  • `json:"price,omitempty"` - omite o campo se o valor for zero
  • `json:"-"` - exclui o campo do JSON inteiramente
type Product struct {
    ID       int     `json:"id"`
    Name     string  `json:"name"`
    Price    float64 `json:"price,omitempty"`
    Internal string  `json:"-"`
}

Apenas campos exportados (iniciados com letra maiúscula) são incluídos na saída JSON.

Experimente 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

	}
}
quiz iconTeste seus conhecimentos

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