Как маршалировать структуру, как если бы это была анонимная структура?

В документации говорится:

Поля анонимных структур обычно маршалируются так, как если бы их внутренние экспортируемые поля были полями внешней структуры.

Например:

type foo struct {
    Foo1 string `json:"foo1"`
    Foo2 string `json:"foo2"`
}

type boo struct {
    Boo1 string `json:"boo1"`
    foo
}

и я делаю это:

s := boo{
    Boo: "boo1",
    foo: foo{
        Foo1: "foo1",
        Foo2: "foo2",
    },
}

b, err := json.MarshalIndent(s, "", "   ")
fmt.Println(string(b))

Я получаю это:

{
    "boo1": "boo1",
    "foo1": "foo1",
    "foo2": "foo2"
}

Но как добиться того же результата, если foo не является анонимной структурой? Значение:

type boo struct {
    Boo string `json:"boo"`
    Foo foo
}

А также распаковать файл json.

Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
3
0
1 216
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Для этого вам нужно реализовать собственный json.Marshaler.

type boo struct {
    Boo1 string `json:"boo1"`
    // "-" will tell encoding/json to ignore this field during (un)marshaling
    Foo foo `json:"-"`
}

func (b boo) MarshalJSON() ([]byte, error) {
    // Declare a new type using boo's definition, this
    // "copies" boo's structure but not its behaviour,
    // i.e. B has same fields as boo, but zero methods,
    // not even MarshalJSON -- this is necessary to avoid
    // infinite recursive calls to MarshalJSON.
    type B boo

    // Declare a new type that *embeds* those structs whose
    // fields you want to be at the same level.
    type T struct {
        B
        foo
    }

    // Create an instance of the new type with its fields
    // set from the source boo instance and marshal it.
    return json.Marshal(T{B: B(b), foo: b.Foo})
}

https://play.golang.org/p/Go1w9quPkMa


Заметка об «анонимности»

Ярлык анонимный, как вы его используете и как он используется в цитируемой вами документации, устарел и неточен. Надлежащая метка для поля без явного имени встроена.

https://golang.org/ref/spec#Struct_types

Поле, объявленное с типом, но без явного имени поля, называется встроенное поле. Встроенное поле должно быть указано как имя типа T или как указатель на имя неинтерфейсного типа *T, а сам T не может быть типом указателя. Неполное имя типа действует как имя поля.

Различие важно, потому что в Go есть такая вещь, как «анонимные поля структуры», они используются довольно часто, но отличаются от встроенных полей. Например:

type T struct {
    // F is an anonymous struct field, or
    // a field of an anonymous struct type.
    // F is not embedded however.
    F struct {
        foo string
        bar int
    }
}

Другие вопросы по теме

Похожие вопросы

Как преобразовать [] float64 в [] байт?
Преобразование сериализованных сообщений protobuf в JSON без предварительной компиляции кода Go
Добавление базовой аутентификации на обратный прокси-сервер на основе Go
Как мне проверить подпись ED25519 длиной 128 символов?
Изменить или создать в зависимости от логического значения
Как проверить, если одно время.Сейчас после другого времени.Время
Как разобрать пароль как массив байтов с помощью волокна
Как запустить приложение «отдельно» в отдельном процессе. Запущенный процесс должен работать в своем собственном сеансе и действовать как демон
Как (предварительно) присоединиться к таблице в пользовательском столбце?
Регулярное выражение для игнорирования нескольких префиксов и сопоставления только в том случае, если у них нет одного или двух конкретных жестко запрограммированных атрибутов?