鉴于以下结构

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"
}

因此,我为UnmarshalJSONFoo(https://play.golang.org/p/6v71eG_Xr98)覆盖了Bar:
package main

import (
    "encoding/json"
    "fmt"
    "time"
)

type Foo struct {
    Thing time.Duration `json:"thing"`
}

type Bar struct {
    Foo
    Entry time.Duration `json:"entry"`
}

func timeConvert(s string) time.Duration {
    if s == "hour" {
        return time.Hour
    }
    if s == "second" {
        return time.Second
    }
    return time.Duration(0)
}

func (t *Foo) UnmarshalJSON(data []byte) error {
    type Alias Foo
    a := struct {
        Thing string `json:"thing"`
        *Alias
    }{Alias: (*Alias)(t)}
    err := json.Unmarshal(data, &a)
    t.Thing = timeConvert(a.Thing)
    fmt.Printf("Foo: %v [%v]\n", *t, err)
    return err
}

func (t *Bar) UnmarshalJSON(data []byte) error {
    type Alias Bar
    a := struct {
        Entry string `json:"entry"`
        *Alias
    }{Alias: (*Alias)(t)}
    err := json.Unmarshal(data, &a)
    t.Entry = timeConvert(a.Entry)
    fmt.Printf("Bar: %v [%v]\n", *t, err)
    return err
}

func main() {
    data := []byte(`{"entry": "second", "thing": "hour"}`)
    json.Unmarshal(data, &Bar{})
}

但是它输出意外:
Foo: {1h0m0s} [<nil>]
Bar: {{1h0m0s} 0s} [<nil>]

为什么Entry值不正确?

最佳答案

感谢mkopriva。我发现这是因为'json.Unmarshal'适用于任何类型,它提示我所有类型均已实现'UnmarshalJSON'函数,但事实并非如此。

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

  • UnmarshalJSON上调用Bar
  • 因为Bar中的匿名结构未实现UnmarshalJSON,所以在其上调用UnmarshalJSON会嵌入结构Foo

  • 这就是为什么匿名结构中的“条目”不会被解码的原因。

    mkopriva建议使用自定义类型来获取自定义解析,但是当您需要将其作为time包中函数的参数传递时,这样做很不方便。我想出了另一种方法(只需解码两次,请参阅https://play.golang.org/p/2ahDX-0hsRt):
    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
    }
    

    09-25 19:43