具有多个嵌入式结构的 Go MarshalJSON 行为
Go MarshalJSON behavior with multiple embedded structs
我正在测试带有嵌入式结构的 go 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))
}
如果您嵌入多个具有相同名称的字段或方法的类型,那么将无法再直接访问这些字段或方法。
x.f
- For a value
x
of type T
or *T
where T
is not a pointer or
interface type, x.f
denotes the field or method at the shallowest depth
in T
where there is such an f
. If there is not exactly one f
with shallowest depth, the selector expression is illegal.
这意味着,给定以下类型集:
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
。您可以在 playground.
上试用
相同的规则适用于方法。由此可见,您的类型 C
不满足 json.Marshaler
接口 因为 它在相同的深度嵌入了 更多 =68=] 实现 MarshalJSON()
方法的类型。您可以在 playground.
上亲自查看
然而,问题仍然存在,即为什么无论如何都使用嵌入式 time.Time
的自定义封送处理。这是因为 time.Time
不仅实现了 json.Marshaler
接口,还实现了 encoding.TextMarshaler
接口(docs & playground). And the json.Marshal
's documentation 表示如下:
Marshal traverses the value v recursively. If an encountered value
implements the Marshaler
interface and is not a nil pointer, Marshal
calls its MarshalJSON
method to produce JSON. If no MarshalJSON
method
is present but the value implements encoding.TextMarshaler
instead,
Marshal calls its MarshalText
method and encodes the result as a JSON
string.
一旦您还A
或B
实现了encoding.TextMarshaler
接口,您就可以see here上述行为成立,然后time.Time
' s MarshalText
方法将不再使用。
我正在测试带有嵌入式结构的 go 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))
}
如果您嵌入多个具有相同名称的字段或方法的类型,那么将无法再直接访问这些字段或方法。
x.f
- For a value
x
of typeT
or*T
whereT
is not a pointer or interface type,x.f
denotes the field or method at the shallowest depth inT
where there is such anf
. If there is not exactly onef
with shallowest depth, the selector expression is illegal.
这意味着,给定以下类型集:
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
。您可以在 playground.
相同的规则适用于方法。由此可见,您的类型 C
不满足 json.Marshaler
接口 因为 它在相同的深度嵌入了 更多 =68=] 实现 MarshalJSON()
方法的类型。您可以在 playground.
然而,问题仍然存在,即为什么无论如何都使用嵌入式 time.Time
的自定义封送处理。这是因为 time.Time
不仅实现了 json.Marshaler
接口,还实现了 encoding.TextMarshaler
接口(docs & playground). And the json.Marshal
's documentation 表示如下:
Marshal traverses the value v recursively. If an encountered value implements the
Marshaler
interface and is not a nil pointer, Marshal calls itsMarshalJSON
method to produce JSON. If noMarshalJSON
method is present but the value implementsencoding.TextMarshaler
instead, Marshal calls itsMarshalText
method and encodes the result as a JSON string.
一旦您还A
或B
实现了encoding.TextMarshaler
接口,您就可以see here上述行为成立,然后time.Time
' s MarshalText
方法将不再使用。