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

В документации указано:

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

Например:

      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.

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
    }
}
Другие вопросы по тегам