Поведение Go MarshalJSON с несколькими встроенными структурами

Я тестирую маршалинг json со встроенными структурами. Однако я вижу, что когда я встраиваю time.Time, почему он всегда переопределяет другие встроенные структуры, даже если они также обеспечивают свою собственную маршалинг? Код ниже всегда распечатывается "0001-01-01T00:00:00Z"

      package main

import (
    "encoding/json"
    "fmt"
    "time"
)

type A struct {
}

func (a A) Print() {
    fmt.Println("A")
}

type B struct {
    B int
}

func (a A) MarshalJSON() ([]byte, error) {
    return []byte(`"a"`), nil
}

func (b B) MarshalJSON() ([]byte, error) {
    return []byte(`"b"`), nil
}

func (a B) Print() {
    fmt.Println("A")
}

type C struct {
    A
    B
    time.Time
    C int `json:"C"`
}

func main() {
    fmt.Println("Hello, 世界")
    c := C{}
    decode, err := json.Marshal(c)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(string(decode))
}

1 ответ

Если вы внедрите несколько типов с одинаковыми именами полей или методов, то эти поля или методы больше не будут доступны напрямую.

Селекторы:

  1. Для значения xтипа или *Tгде не указатель или тип интерфейса, x.fобозначает поле или метод на самой малой глубине в Tгде есть такой. Если нет точно одного fс наименьшей глубиной выражение селектора является недопустимым.

Это означает, что для следующего набора типов:

      type S1 struct { F string }

type S2 struct { F string }

type S3 struct {
    S1
    S2
}

выражение s3.Fявляется незаконным:

      var s3 S3
_ = s3.F // ambiguous selector s3.F

это потому, что их больше одного Fна самой малой глубине . Вы можете попробовать это на детской площадке .

Те же правила применяются к методам. Отсюда следует, что ваш тип CНЕ удовлетворяет интерфейс, потому что он встраивает на той же глубине более одного типа, реализующего интерфейс.MarshalJSON()метод. Вы сами можете убедиться в этом на детской площадке .


Тогда, однако, все еще остается вопрос о том, почему встроенный настраиваемый маршалинг используется независимо. Это связано с тем, что реализует не только json.Marshalerинтерфейс, но и интерфейс (документы и игровая площадка ). И json.Marshalдокументация говорит следующее:

Маршал рекурсивно обходит значение v. Если встречающееся значение реализует Marshalerинтерфейс и не является нулевым указателем, Marshal вызывает свой метод для создания JSON. Если нет MarshalJSONметод присутствует, но вместо этого реализуется значение, Marshal вызывает его метод и кодирует результат в виде строки JSON.

Здесь вы можете видеть , что поведение, описанное выше, сохраняется, если у вас также есть Aили же Bреализовать encoding.TextMarshalerинтерфейс, затем time.Timeх MarshalTextметод больше не будет использоваться.

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