Поиск…
Синтаксис
- func Маршал (v интерфейс {}) ([] байт, ошибка)
- func Unmarshal (data [] byte, v interface {}) error
замечания
Пакет "encoding/json"
Package json реализует кодирование и декодирование объектов JSON в Go
.
Типы в JSON вместе со своими конкретными типами в Go:
Тип JSON | Go Concrete Type |
---|---|
логический | BOOL |
чисел | float64 или int |
строка | строка |
ноль | ноль |
Базовая кодировка JSON
json.Marshal
из пакета "encoding/json"
кодирует значение JSON.
Параметр - это значение для кодирования. Возвращаемые значения представляют собой массив байтов, представляющих входной сигнал JSON (при успешном завершении), и ошибку (при сбое).
decodedValue := []string{"foo", "bar"}
// encode the value
data, err := json.Marshal(decodedValue)
// check if the encoding is successful
if err != nil {
panic(err)
}
// print out the JSON-encoded string
// remember that data is a []byte
fmt.Println(string(data))
// "["foo","bar"]"
Вот некоторые основные примеры кодирования для встроенных типов данных:
var data []byte
data, _ = json.Marshal(1)
fmt.Println(string(data))
// 1
data, _ = json.Marshal("1")
fmt.Println(string(data))
// "1"
data, _ = json.Marshal(true)
fmt.Println(string(data))
// true
data, _ = json.Marshal(map[string]int{"London": 18, "Rome": 30})
fmt.Println(string(data))
// {"London":18,"Rome":30}
Кодирование простых переменных полезно для понимания того, как кодирование JSON работает в Go. Однако в реальном мире вы, скорее всего, кодируете более сложные данные, хранящиеся в структурах .
Базовое декодирование JSON
json.Unmarshal
из пакета "encoding/json"
декодирует значение JSON в значение, указанное данной переменной.
Параметры - это значение для декодирования в []bytes
и переменная, используемая в качестве хранилища для де-сериализованного значения. Возвращаемое значение - ошибка (при сбое).
encodedValue := []byte(`{"London":18,"Rome":30}`)
// generic storage for the decoded JSON
var data map[string]interface{}
// decode the value into data
// notice that we must pass the pointer to data using &data
err := json.Unmarshal(encodedValue, &data)
// check if the decoding is successful
if err != nil {
panic(err)
}
fmt.Println(data)
map[London:18 Rome:30]
Обратите внимание, как в приведенном выше примере мы заранее знали тип ключа и значение. Но это не всегда так. Фактически, в большинстве случаев JSON содержит смешанные типы значений.
encodedValue := []byte(`{"city":"Rome","temperature":30}`)
// generic storage for the decoded JSON
var data map[string]interface{}
// decode the value into data
if err := json.Unmarshal(encodedValue, &data); err != nil {
panic(err)
}
// if you want to use a specific value type, we need to cast it
temp := data["temperature"].(float64)
fmt.Println(temp) // 30
city := data["city"].(string)
fmt.Println(city) // "Rome"
В последнем примере выше мы использовали общую карту для хранения декодированного значения. Мы должны использовать map[string]interface{}
потому что знаем, что ключи являются строками, но мы не знаем тип их значений заранее.
Это очень простой подход, но он также крайне ограничен. В реальном мире вы обычно декодируете JSON в настраиваемый тип struct
.
Декодирование данных JSON из файла
Данные JSON также могут считываться из файлов.
Предположим, у нас есть файл с именем data.json
со следующим содержимым:
[
{
"Name" : "John Doe",
"Standard" : 4
},
{
"Name" : "Peter Parker",
"Standard" : 11
},
{
"Name" : "Bilbo Baggins",
"Standard" : 150
}
]
В следующем примере читается файл и декодируется содержимое:
package main
import (
"encoding/json"
"fmt"
"log"
"os"
)
type Student struct {
Name string
Standard int `json:"Standard"`
}
func main() {
// open the file pointer
studentFile, err := os.Open("data.json")
if err != nil {
log.Fatal(err)
}
defer studentFile.Close()
// create a new decoder
var studentDecoder *json.Decoder = json.NewDecoder(studentFile)
if err != nil {
log.Fatal(err)
}
// initialize the storage for the decoded data
var studentList []Student
// decode the data
err = studentDecoder.Decode(&studentList)
if err != nil {
log.Fatal(err)
}
for i, student := range studentList {
fmt.Println("Student", i+1)
fmt.Println("Student name:", student.Name)
fmt.Println("Student standard:", student.Standard)
}
}
Файл data.json
должен находиться в том же каталоге исполняемой программы Go. Для получения дополнительной информации о том, как работать с файлами в Go, прочитайте документацию по файлу ввода-вывода Go.
Использование анонимных структур для декодирования
Целью использования анонимных структур является декодирование только информации, о которой мы заботимся, не засоряя наше приложение типами, которые используются только в одной функции.
jsonBlob := []byte(`
{
"_total": 1,
"_links": {
"self": "https://api.twitch.tv/kraken/channels/foo/subscriptions?direction=ASC&limit=25&offset=0",
"next": "https://api.twitch.tv/kraken/channels/foo/subscriptions?direction=ASC&limit=25&offset=25"
},
"subscriptions": [
{
"created_at": "2011-11-23T02:53:17Z",
"_id": "abcdef0000000000000000000000000000000000",
"_links": {
"self": "https://api.twitch.tv/kraken/channels/foo/subscriptions/bar"
},
"user": {
"display_name": "bar",
"_id": 123456,
"name": "bar",
"staff": false,
"created_at": "2011-06-16T18:23:11Z",
"updated_at": "2014-10-23T02:20:51Z",
"logo": null,
"_links": {
"self": "https://api.twitch.tv/kraken/users/bar"
}
}
}
]
}
`)
var js struct {
Total int `json:"_total"`
Links struct {
Next string `json:"next"`
} `json:"_links"`
Subs []struct {
Created string `json:"created_at"`
User struct {
Name string `json:"name"`
ID int `json:"_id"`
} `json:"user"`
} `json:"subscriptions"`
}
err := json.Unmarshal(jsonBlob, &js)
if err != nil {
fmt.Println("error:", err)
}
fmt.Printf("%+v", js)
Вывод: {Total:1 Links:{Next:https://api.twitch.tv/kraken/channels/foo/subscriptions?direction=ASC&limit=25&offset=25} Subs:[{Created:2011-11-23T02:53:17Z User:{Name:bar ID:123456}}]}
В общем случае см. Также: http://stackoverflow.com/documentation/go/994/json/4111/encoding-decoding-go-structs
Настройка полей структуры JSON
Рассмотрим следующий пример:
type Company struct {
Name string
Location string
}
Скрыть / пропустить определенные поля
Чтобы экспортировать Revenue
и Sales
, но скрыть их от кодирования / декодирования, используйте json:"-"
или переименуйте переменную, чтобы начать с строчной буквы. Обратите внимание, что это предотвращает видимость переменной вне пакета.
type Company struct {
Name string `json:"name"`
Location string `json:"location"`
Revenue int `json:"-"`
sales int
}
Игнорировать пустое поле
Чтобы предотвратить включение Location
в JSON, когда оно установлено на его нулевое значение, добавьте ,omitempty
в тег json
.
type Company struct {
Name string `json:"name"`
Location string `json:"location,omitempty"`
}
Структуры Marshaling с частными полями
Как хороший разработчик, вы создали следующую структуру с экспортированными и неэкспонированными полями:
type MyStruct struct {
uuid string
Name string
}
Пример на игровой площадке: https://play.golang.org/p/Zk94Il2ANZ
Теперь вы хотите, чтобы Marshal()
эта структура была в действительной JSON для хранения в чем-то вроде etcd. Однако, поскольку uuid
не экспортируется, json.Marshal()
пропускает его. Что делать? Используйте анонимную структуру и интерфейс json.MarshalJSON()
! Вот пример:
type MyStruct struct {
uuid string
Name string
}
func (m MyStruct) MarshalJSON() ([]byte, error {
j, err := json.Marshal(struct {
Uuid string
Name string
}{
Uuid: m.uuid,
Name: m.Name,
})
if err != nil {
return nil, err
}
return j, nil
}
Пример на игровой площадке: https://play.golang.org/p/Bv2k9GgbzE
Кодирование / декодирование с использованием структур Go
Предположим, у нас есть следующая struct
которая определяет тип City
:
type City struct {
Name string
Temperature int
}
Мы можем кодировать / декодировать значения City, используя пакет encoding/json
.
Прежде всего, нам нужно использовать метаданные Go, чтобы сообщить кодировщику соответствие между строковыми полями и ключами JSON.
type City struct {
Name string `json:"name"`
Temperature int `json:"temp"`
// IMPORTANT: only exported fields will be encoded/decoded
// Any field starting with a lower letter will be ignored
}
Чтобы этот пример был прост, мы объявим явное соответствие между полями и ключами. Однако вы можете использовать несколько вариантов json:
metadata, как описано в документах .
ВАЖНО: Сегментируются / десериализуются только экспортируемые поля (поля с именем). Например, если вы назовете поле t emperature, оно будет проигнорировано, даже если вы установите метаданные json
.
кодирование
Чтобы закодировать структуру City
, используйте json.Marshal
как в базовом примере:
// data to encode
city := City{Name: "Rome", Temperature: 30}
// encode the data
bytes, err := json.Marshal(city)
if err != nil {
panic(err)
}
fmt.Println(string(bytes))
// {"name":"Rome","temp":30}
расшифровка
Чтобы декодировать структуру City
, используйте json.Unmarshal
как в базовом примере:
// data to decode
bytes := []byte(`{"name":"Rome","temp":30}`)
// initialize the container for the decoded data
var city City
// decode the data
// notice the use of &city to pass the pointer to city
if err := json.Unmarshal(bytes, &city); err != nil {
panic(err)
}
fmt.Println(city)
// {Rome 30}