Поведение 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 ответ
Если вы внедрите несколько типов с одинаковыми именами полей или методов, то эти поля или методы больше не будут доступны напрямую.
- Для значения
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
метод больше не будет использоваться.