Json 解组嵌套结构的字段无效
给定以下结构Json 解组嵌套结构的字段无效,json,go,types,marshalling,unmarshalling,Json,Go,Types,Marshalling,Unmarshalling,给定以下结构 type Foo struct { Thing time.Duration `json:"thing"` } type Bar struct { Foo Entry time.Duration `json:"entry"` } 我想自定义time.Duration格式并从json字符串加载Bar值,如: { "thing": "hour", "entry": "second" } 因此,我为Foo和Bar()重写UnmarshalJSON: 但
type Foo struct {
Thing time.Duration `json:"thing"`
}
type Bar struct {
Foo
Entry time.Duration `json:"entry"`
}
我想自定义time.Duration
格式并从json字符串加载Bar
值,如:
{
"thing": "hour",
"entry": "second"
}
因此,我为Foo
和Bar
()重写UnmarshalJSON
:
但它产生了意想不到的结果:
Foo: {1h0m0s} [<nil>]
Bar: {{1h0m0s} 0s} [<nil>]
Foo:{1h0m0s}[]
条:{{1h0m0s}0s}[]
为什么
条目
值不正确?感谢mkopriva。我发现,因为“json.Unmarshal”适用于任何类型,它给了我一个提示,所有类型都实现了“UnmarshalJSON”函数,但事实并非如此
在“Bar”上调用“json.Unmarshal”实际上将执行以下操作:
Bar
上调用UnmarshalJSON
Bar
中的匿名结构没有实现UnmarshalJSON
,所以在它的嵌入结构Foo
上调用UnmarshalJSON
time
包中函数的参数传递时,这会带来不便。我找到了另一种方法(只需解组两次,请参见):
谢谢你的mkopriva。我发现,因为“json.Unmarshal”适用于任何类型,它给了我一个提示,所有类型都实现了“UnmarshalJSON”函数,但事实并非如此 在“Bar”上调用“json.Unmarshal”实际上将执行以下操作:
Bar
上调用UnmarshalJSON
Bar
中的匿名结构没有实现UnmarshalJSON
,所以在它的嵌入结构Foo
上调用UnmarshalJSON
time
包中函数的参数传递时,这会带来不便。我找到了另一种方法(只需解组两次,请参见):
条目的值为0s,它是预期值ithink@loggerhead问题是您正在嵌入别名,虽然使用别名类型可以避免在Bar上递归调用UnmarshalJSON,但它仍然会在Foo上调用它,Foo嵌入在Bar中,因此也嵌入在alias中,因此,Foo的UnmarshalJSON中的逻辑被执行,因此“entry”永远不会被取消编组,因为它在Foo中不存在。@loggerhead如果您能够更改entry和Thing的类型,我建议您创建一个自定义持续时间类型。()@mkopriva你说得对,谢谢!但是自定义的持续时间类型不方便调用
time
包中的函数。我想出一个解决办法,我会自己回答。再次感谢:)条目的值为0s,这是预期值ithink@loggerhead问题是您正在嵌入别名,虽然使用别名类型可以避免在Bar上递归调用UnmarshalJSON,但它仍然会在Foo上调用它,Foo嵌入在Bar中,因此也嵌入在alias中,因此,Foo的UnmarshalJSON中的逻辑被执行,因此“entry”永远不会被取消编组,因为它在Foo中不存在。@loggerhead如果您能够更改entry和Thing的类型,我建议您创建一个自定义持续时间类型。()@mkopriva你说得对,谢谢!但是自定义的持续时间类型不方便调用time
包中的函数。我想出一个解决办法,我会自己回答。再次感谢:)
Foo: {1h0m0s} [<nil>]
Bar: {{1h0m0s} 0s} [<nil>]
func (t *Bar) UnmarshalJSON(data []byte) error {
type Alias Bar
if err := json.Unmarshal(data, (*Alias)(t)); err != nil {
return err
}
var tmp struct {
Entry string `json:"entry"`
}
err := json.Unmarshal(data, &tmp)
t.Entry = timeConvert(tmp.Entry)
fmt.Printf("Bar: %v [%v]\n", *t, err)
return err
}