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
  • 这就是为什么匿名结构中的“条目”不会被解组

    mkopriva建议使用自定义类型来获取自定义解析,但当需要将其作为
    time
    包中函数的参数传递时,这会带来不便。我找到了另一种方法(只需解组两次,请参见):


    谢谢你的mkopriva。我发现,因为“json.Unmarshal”适用于任何类型,它给了我一个提示,所有类型都实现了“UnmarshalJSON”函数,但事实并非如此

    在“Bar”上调用“json.Unmarshal”实际上将执行以下操作:

  • Bar
    上调用
    UnmarshalJSON
  • 因为
    Bar
    中的匿名结构没有实现
    UnmarshalJSON
    ,所以在它的嵌入结构
    Foo
    上调用
    UnmarshalJSON
  • 这就是为什么匿名结构中的“条目”不会被解组

    mkopriva建议使用自定义类型来获取自定义解析,但当需要将其作为
    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
    }