логотип PurpleSchool
логотип PurpleSchool

Обработка JSON в Go

Автор

Александр Гольцман

Обработка JSON в Go

JSON (JavaScript Object Notation) — один из самых популярных форматов для хранения и передачи данных. В языке программирования Go для работы с JSON предусмотрен стандартный пакет encoding/json, который позволяет кодировать и декодировать данные с минимальными усилиями. В этой статье мы разберём, как сериализовать и десериализовать данные в JSON, а также рассмотрим полезные нюансы и лучшие практики.

Основы работы с JSON в Go

В Go JSON представлен строками, которые можно преобразовать в структуры (struct) или карты (map). Основные операции с JSON включают:

  • Кодирование (сериализацию) структур в JSON.
  • Декодирование (разбор) JSON в структуры.
  • Обработку JSON с динамической структурой.

Пакет encoding/json предоставляет удобные функции json.Marshal (для кодирования) и json.Unmarshal (для декодирования). Давайте посмотрим на их использование.

Сериализация структуры в JSON

Когда нам нужно представить данные в формате JSON, мы можем использовать json.Marshal, которая преобразует структуру в байтовый срез ([]byte).

Пример:

package main

import (
    "encoding/json"
    "fmt"
)

// Определяем структуру для сериализации
type User struct {
    Name  string `json:"name"`
    Age   int    `json:"age"`
    Email string `json:"email"`
}

func main() {
    user := User{Name: "Иван", Age: 30, Email: "ivan@example.com"}

    jsonData, err := json.Marshal(user)
    if err != nil {
        fmt.Println("Ошибка при сериализации:", err)
        return
    }

    fmt.Println("JSON:", string(jsonData))
}

Разбор кода:

  • Мы создаём структуру User с тремя полями.
  • Теги json:"name" позволяют задать название полей в JSON, если оно должно отличаться от названия в Go.
  • json.Marshal кодирует структуру в JSON-строку.

Обратите внимание: json.Marshal возвращает байтовый срез, поэтому мы приводим его к строке string(jsonData), чтобы вывести результат.

Десериализация JSON в структуру

Теперь разберём, как преобразовать JSON в структуру. Здесь используется функция json.Unmarshal.

Пример:

package main

import (
    "encoding/json"
    "fmt"
)

// Определяем структуру
type User struct {
    Name  string `json:"name"`
    Age   int    `json:"age"`
    Email string `json:"email"`
}

func main() {
    jsonString := `{"name": "Мария", "age": 25, "email": "maria@example.com"}`

    var user User
    err := json.Unmarshal([]byte(jsonString), &user)
    if err != nil {
        fmt.Println("Ошибка при разборе JSON:", err)
        return
    }

    fmt.Println("Имя:", user.Name)
    fmt.Println("Возраст:", user.Age)
    fmt.Println("Email:", user.Email)
}

Что здесь происходит?

  • json.Unmarshal принимает JSON-данные в виде []byte и указатель на структуру, куда записывать результат.
  • После успешного выполнения данные из JSON копируются в структуру user.

Работа с JSON, структура которого неизвестна заранее

Иногда нам нужно обработать JSON, структура которого заранее неизвестна или может изменяться. В таком случае можно использовать map[string]interface{} или interface{}.

Пример:

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    jsonString := `{"name": "Анна", "age": 22, "skills": ["Go", "Python", "JavaScript"]}`

    var data map[string]interface{}
    err := json.Unmarshal([]byte(jsonString), &data)
    if err != nil {
        fmt.Println("Ошибка при разборе JSON:", err)
        return
    }

    fmt.Println("Имя:", data["name"])
    fmt.Println("Возраст:", data["age"])
    fmt.Println("Навыки:", data["skills"])
}

Здесь JSON разбирается в карту (map), где ключи — строки, а значения могут быть любыми (interface{}). Однако при использовании interface{} нужно дополнительно приводить типы, если мы хотим работать с конкретными значениями.

Обработка вложенных структур

Когда JSON содержит вложенные объекты, мы можем использовать составные структуры.

Пример:

package main

import (
    "encoding/json"
    "fmt"
)

// Определяем вложенные структуры
type Address struct {
    City  string `json:"city"`
    State string `json:"state"`
}

type Person struct {
    Name    string  `json:"name"`
    Age     int     `json:"age"`
    Address Address `json:"address"`
}

func main() {
    jsonString := `{"name": "Дмитрий", "age": 35, "address": {"city": "Москва", "state": "Россия"}}`

    var person Person
    err := json.Unmarshal([]byte(jsonString), &person)
    if err != nil {
        fmt.Println("Ошибка при разборе JSON:", err)
        return
    }

    fmt.Println("Имя:", person.Name)
    fmt.Println("Город:", person.Address.City)
    fmt.Println("Страна:", person.Address.State)
}

Настройка кодирования JSON

По умолчанию json.Marshal форматирует JSON в одну строку. Если вам нужен читаемый формат, используйте json.MarshalIndent.

Пример:

package main

import (
    "encoding/json"
    "fmt"
)

// Определяем структуру
type User struct {
    Name  string `json:"name"`
    Age   int    `json:"age"`
    Email string `json:"email"`
}

func main() {
    user := User{Name: "Екатерина", Age: 28, Email: "katya@example.com"}

    jsonData, err := json.MarshalIndent(user, "", "  ")
    if err != nil {
        fmt.Println("Ошибка при сериализации:", err)
        return
    }

    fmt.Println(string(jsonData))
}

Здесь json.MarshalIndent(user, "", " ") добавляет отступы, делая JSON удобочитаемым.

Заключение

Пакет encoding/json в Go позволяет удобно работать с JSON-данными. Основные моменты, которые стоит запомнить:

  • Для сериализации используйте json.Marshal, а для удобного формата — json.MarshalIndent.
  • Для десериализации применяется json.Unmarshal.
  • Если структура неизвестна заранее, можно использовать map[string]interface{}.
  • Для вложенных объектов создавайте соответствующие структуры.

Работа с JSON в Go — это основа многих веб-приложений и сервисов. В этой статье мы разобрали, как сериализовать и десериализовать данные в JSON, а также рассмотрели полезные нюансы и лучшие практики. Удачи в постижении нового!

Карта развития разработчика

Получите полную карту развития разработчика по всем направлениям: frontend, backend, devops, mobile