具有多个嵌入结构的 Go MarshalJSON 行为

Le *_*ong 2 go encoding-json-go

我正在测试带有嵌入式结构的 go json 封送处理。但是,我发现当我嵌入 time.Time 时,为什么它总是覆盖其他嵌入的结构,即使它们也提供自己的自定义封送处理?下面的代码总是打印出来"0001-01-01T00:00:00Z"

\n
package main\n\nimport (\n    "encoding/json"\n    "fmt"\n    "time"\n)\n\ntype A struct {\n}\n\nfunc (a A) Print() {\n    fmt.Println("A")\n}\n\ntype B struct {\n    B int\n}\n\nfunc (a A) MarshalJSON() ([]byte, error) {\n    return []byte(`"a"`), nil\n}\n\nfunc (b B) MarshalJSON() ([]byte, error) {\n    return []byte(`"b"`), nil\n}\n\nfunc (a B) Print() {\n    fmt.Println("A")\n}\n\ntype C struct {\n    A\n    B\n    time.Time\n    C int `json:"C"`\n}\n\nfunc main() {\n    fmt.Println("Hello, \xe4\xb8\x96\xe7\x95\x8c")\n    c := C{}\n    decode, err := json.Marshal(c)\n    if err != nil {\n        fmt.Println(err)\n    }\n    fmt.Println(string(decode))\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

mko*_*iva 5

如果您嵌入具有相同名称字段或方法的多个类型,则将无法再直接访问这些字段或方法。

选择器

x.f

  1. x对于typeT*TwhereT不是指针或接口类型的值,表示存在此类 的x.f最浅深度的字段或方法。如果不存在深度最浅的选择器表达式 ,则该选择器表达式是非法的Tff

这意味着,给定以下一组类型:

type S1 struct { F string }

type S2 struct { F string }

type S3 struct {
    S1
    S2
}
Run Code Online (Sandbox Code Playgroud)

该表达式s3.F是非法的:

var s3 S3
_ = s3.F // ambiguous selector s3.F
Run Code Online (Sandbox Code Playgroud)

这是因为在最浅的深度不止一个F你可以在操场上尝试一下。

相同的规则适用于方法。由此可见,您的类型C不满足json.Marshaler接口,因为它在相同的深度嵌入了不止一种实现该MarshalJSON()方法的类型。您可以在操场上亲自看到这一点。


然而,问题仍然是为什么time.Time无论如何都要使用嵌入式的自定义封送处理。这是因为time.Time不仅实现了json.Marshaler接口,还encoding.TextMarshaler实现了接口(文档游乐场)。的json.Marshal文档说明如下:

Marshal 递归地遍历值 v。如果遇到的值实现了Marshaler接口并且不是 nil 指针,Marshal 会调用其MarshalJSON方法来生成 JSON。如果不MarshalJSON存在任何方法,但值实现encoding.TextMarshaler了,Marshal 会调用其MarshalText方法并将结果编码为 JSON 字符串

您可以在这里看到A,一旦您也拥有或B实现了该接口,上述行为就成立encoding.TextMarshaler,那么time.Time'sMarshalText方法将不再被使用。