Menu
Coddy logo textTech

encoding/json со структурами

Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy — урок 76 из 107.

Пакет encoding/json позволяет преобразовывать структуры Go в JSON и обратно. Это необходимо для API, конфигурационных файлов и хранения данных. Теги структур управляют тем, как поля сопоставляются с ключами JSON.

Чтобы преобразовать структуру в JSON, используйте 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}
}

Теги структур, такие как `json:"name"`, определяют имена ключей JSON. Без тегов Go использует имя поля напрямую. В вывод JSON включаются только экспортируемые поля (начинающиеся с заглавной буквы).

Чтобы преобразовать JSON обратно в структуру, используйте json.Unmarshal:

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

Распространенные параметры тегов включают omitempty для пропуска нулевых значений и - для полного игнорирования поля:

type Product struct {
    ID       int    `json:"id"`
    Name     string `json:"name"`
    Price    float64 `json:"price,omitempty"`
    Internal string `json:"-"`
}

С использованием omitempty, если Price равно нулю, оно не появится в JSON. Поле Internal никогда не включается, независимо от его значения.

challenge icon

Задание

Легко

Давайте создадим систему каталога фильмов, которая преобразует структуры Go в JSON и наоборот! Вы попрактикуетесь в маршалинге структур в JSON и анмаршалинге JSON обратно в структуры, используя теги структур для управления именами полей JSON.

Вы организуете свой код в двух файлах:

  • movie.go: Определите модель данных фильма с соответствующими тегами JSON.

    Создайте структуру Movie со следующими полями и сопоставлениями JSON:

    • Title (string) сопоставляется с "title"
    • Director (string) сопоставляется с "director"
    • Year (int) сопоставляется с "year"
    • Rating (float64) сопоставляется с "rating" с параметром omitempty, чтобы у фильмов без рейтинга поле рейтинга не отображалось
    • InternalID (string) должен быть полностью исключен из JSON с помощью "-"

    Создайте функцию ToJSON(m Movie) string, которая преобразует Movie в строку JSON. Также создайте FromJSON(jsonStr string) Movie, которая разбирает строку JSON обратно в структуру Movie.

  • main.go: Продемонстрируйте преобразование JSON в обоих направлениях.

    Считайте тип операции ("encode" или "decode").

    Для "encode": Считайте данные фильма (название, режиссер, год, рейтинг) на отдельных строках. Создайте Movie с InternalID равным "internal-123", преобразуйте его в JSON и выведите результат.

    Для "decode": Считайте строку JSON, преобразуйте ее в структуру Movie и выведите данные фильма в следующем формате:

    Title: [title]
    Director: [director]
    Year: [year]
    Rating: [rating]

    Выведите рейтинг с одним десятичным знаком. Если рейтинг равен 0 (отсутствует в JSON), выведите вместо него Rating: N/A.

Будут предоставлены следующие входные данные:

  • Строка 1: Тип операции ("encode" или "decode")
  • Для encode: название, режиссер, год, рейтинг (четыре строки)
  • Для decode: строка JSON (одна строка)

Например, при вводе:

encode
Inception
Christopher Nolan
2010
8.8

Ваш вывод должен быть:

{"title":"Inception","director":"Christopher Nolan","year":2010,"rating":8.8}

Обратите внимание, что InternalID не появляется в выводе из-за тега "-".

И при вводе:

encode
The Matrix
Wachowskis
1999
0

Ваш вывод должен быть:

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

Обратите внимание, что rating опущен, так как он равен нулю и имеет тег omitempty.

И при вводе:

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

Ваш вывод должен быть:

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

И при вводе:

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

Ваш вывод должен быть:

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

Шпаргалка

Пакет encoding/json преобразует структуры Go в JSON и наоборот с помощью json.Marshal и json.Unmarshal.

Чтобы преобразовать структуру в 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}

Чтобы преобразовать JSON обратно в структуру:

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

Теги структур управляют сопоставлением полей JSON:

  • `json:"name"` — сопоставляет поле с ключом JSON "name"
  • `json:"price,omitempty"` — пропускает поле, если его значение является нулевым (zero value)
  • `json:"-"` — полностью исключает поле из JSON
type Product struct {
    ID       int     `json:"id"`
    Name     string  `json:"name"`
    Price    float64 `json:"price,omitempty"`
    Internal string  `json:"-"`
}

В вывод JSON включаются только экспортируемые поля (начинающиеся с заглавной буквы).

Попробуйте сами

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Чтение типа операции
	operation, _ := reader.ReadString('\n')
	operation = strings.TrimSpace(operation)

	if operation == "encode" {
		// Чтение данных о фильме
		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: Создать структуру Movie с прочитанными значениями
		// Установить InternalID в значение "internal-123"
		// Преобразовать в JSON с помощью ToJSON и вывести результат

	} else if operation == "decode" {
		// Чтение строки JSON
		jsonStr, _ := reader.ReadString('\n')
		jsonStr = strings.TrimSpace(jsonStr)

		// TODO: Преобразовать JSON в Movie с помощью FromJSON
		// Вывести данные о фильме в требуемом формате
		// Использовать fmt.Sprintf("%.1f", rating) для форматирования рейтинга
		// Если рейтинг равен 0, вывести "Rating: N/A" вместо него

	}
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

11Стандартная библиотека и ООП

io.Reader и io.Writersort.InterfaceИнтерфейс fmt.Stringerencoding/json со структурамиИнтерфейс http.HandlerПовторение: модели REST API