英文:
Go MarshalJSON behavior with multiple embedded structs
问题
我正在测试使用嵌入结构进行go json marshaling。然而,我发现当我嵌入time.Time时,为什么它总是覆盖其他嵌入结构,即使它们也提供了自己的自定义marshaling?下面的代码总是打印出"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))
}
英文:
I'm testing out go json marshaling with embedded structs. However, I see that when I embed time.Time, why does it always override the other embedded structs even though they also provide their own custom marshaling? The code below always print out "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
得分: 5
如果嵌入了具有相同名称字段或方法的多个类型,则这些字段或方法将不再直接可访问。
选择器:
- 对于类型为
T
或*T
(其中T
不是指针或接口类型)的值x
,x.f
表示在T
中最浅深度处存在的字段或方法f
。如果最浅深度处不止一个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
。你可以在playground上尝试。
相同的规则适用于方法。由此可知,你的类型C
不满足json.Marshaler
接口,因为它在相同深度上嵌入了多个实现MarshalJSON()
方法的类型。你可以在playground上自行验证。
然而,问题仍然存在,为什么嵌入的time.Time
的自定义编组仍然被使用。这是因为time.Time
不仅实现了json.Marshaler
接口,还实现了encoding.TextMarshaler
接口(文档和playground)。而且,json.Marshal
的文档中如下所述:
Marshal
递归地遍历值v
。如果遇到的值实现了Marshaler
接口且不是空指针,则Marshal
调用其MarshalJSON
方法生成JSON。如果没有MarshalJSON
方法,但该值实现了encoding.TextMarshaler
接口,Marshal
将调用其MarshalText
方法并将结果编码为JSON字符串。
你可以在这里看到,一旦A
或B
也实现了encoding.TextMarshaler
接口,那么time.Time
的MarshalText
方法将不再被使用。
英文:
If you embed multiple types that have identically named fields or methods, then those fields or methods will not be accessible directly anymore.
> x.f
> 1. 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.
That means that, given the following set of types:
type S1 struct { F string }
type S2 struct { F string }
type S3 struct {
S1
S2
}
the expression s3.F
is illegal:
var s3 S3
_ = s3.F // ambiguous selector s3.F
this is because there are more than one F
at the shallowest depth. You can try it on playground.
The same rules apply to methods. From this it follows that your type C
does NOT satisfy the json.Marshaler
interface because it embeds, at the same depth, more that one type that implements the MarshalJSON()
method. You can see that for yourself on playground.
Then, however, the question still remains as to why the embedded time.Time
's custom marshaling is used regardless. This is because time.Time
implements not only the json.Marshaler
interface but also the encoding.TextMarshaler
interface (docs & playground). And the json.Marshal
's documentation says the following:
> 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.
You can see here that the behaviour described above holds once you also have A
or B
implement the encoding.TextMarshaler
interface, then the time.Time
's MarshalText
method will not be used anymore.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论