Интерфейс json.Marshaler
Интерфейс json.Marshaler предоставляет механизм для кастомной маршализации JSON.
Он содержит метод MarshalJSON, который возвращает байтовый срез JSON-данных и ошибку.
Реализуя этот интерфейс для пользовательского типа, мы можем определить собственный
формат представления данных в JSON, отличный от стандартного.
Синтаксис
type Marshaler interface {
MarshalJSON() ([]byte, error)
}
Пример
Рассмотрим структуру, представляющую пользователя. Стандартная маршализация выведет все поля в JSON. Мы хотим изменить формат вывода, скрыв некоторые поля:
package main
import (
"encoding/json"
"fmt"
"log"
)
type User struct {
Name string
Password string
Age int
}
// Реализация MarshalJSON
func (u User) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Name string `json:"name"`
Age int `json:"age"`
}{
Name: u.Name,
Age: u.Age,
})
}
func main() {
user := User{
Name: "alice",
Password: "secret123",
Age: 30,
}
res, err := json.Marshal(user)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(res))
}
Результат выполнения кода:
{"name":"alice","age":30}
Как видим, поле Password не попало в финальный JSON, а имена полей
были приведены к нижнему регистру.
Пример
Теперь реализуем маршализацию для типа данных с нестандартным форматом.
Создадим тип Duration, который будет выводиться в JSON как строка
в формате "Xh Ym Zs":
package main
import (
"encoding/json"
"fmt"
"log"
"time"
)
type Duration struct {
Seconds int
}
func (d Duration) MarshalJSON() ([]byte, error) {
hours := d.Seconds / 3600
minutes := (d.Seconds % 3600) / 60
seconds := d.Seconds % 60
var s string
if hours > 0 {
s += fmt.Sprintf("%dh ", hours)
}
if minutes > 0 || hours > 0 {
s += fmt.Sprintf("%dm ", minutes)
}
s += fmt.Sprintf("%ds", seconds)
return []byte(fmt.Sprintf("%q", s)), nil
}
type Task struct {
Title string `json:"title"`
Duration Duration `json:"duration"`
}
func main() {
task := Task{
Title: "Complete project",
Duration: Duration{Seconds: 3665},
}
res, err := json.Marshal(task)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(res))
}
Результат выполнения кода:
{"title":"Complete project","duration":"1h 1m 5s"}
Пример
Интерфейс json.Marshaler также позволяет изменять структуру данных
на основе условий или преобразов