编组JSON时如何内联字段?

时间:2017-03-28 18:53:46

标签: json go marshalling

我的类型MonthYear定义为

type MonthYear time.Time

func (my *MonthYear) MarshalJSON() ([]byte, error) {
    t := time.Time(*my)

    return json.Marshal(&struct {
        Month int `json:"month"`
        Year  int `json:"year"`
    }{
        Month: int(t.Month()) - 1,
        Year:  t.Year(),
    })
}

我包括很多不同的结构,比如

type Event struct {
    Name string `json:"name"`
    Date MonthYear
}

type Item struct {
    Category string `json:"category"`
    Date     MonthYear
}

如何内联MonthYear类型以便生成的JSON没有任何嵌入对象?

我希望结果看起来像{ "name": "party", "month": 2, "year": 2017 }{ "category": "art", "month": 3, "year": 2016 },而不必为每个结构编写MarshalJSON。

1 个答案:

答案 0 :(得分:3)

我知道这不是您希望收到的答案,但在encoding/json包中添加内联支持之前,您可以使用以下解决方法:

使你的MonthYear成为一个结构,例如:

type MonthYear struct {
    t     time.Time
    Month int `json:"month"`
    Year  int `json:"year"`
}

一个可选的构造函数,可以轻松创建:

func NewMonthYear(t time.Time) MonthYear {
    return MonthYear{
        t:     t,
        Month: int(t.Month()) - 1,
        Year:  t.Year(),
    }
}

并使用embedding(匿名字段)而不是常规(命名)字段来获得"展平" /在JSON表示中内联:

type Event struct {
    Name string `json:"name"`
    MonthYear
}

type Item struct {
    Category string `json:"category"`
    MonthYear
}

作为额外内容,您可以直接引用字段,例如Event.YearEvent.Month,这很不错。

测试它:

evt := Event{Name: "party", MonthYear: NewMonthYear(time.Now())}
fmt.Println(json.NewEncoder(os.Stdout).Encode(evt), evt.Year)

itm := Item{Category: "Tool", MonthYear: NewMonthYear(time.Now())}
fmt.Println(json.NewEncoder(os.Stdout).Encode(itm))

输出(在Go Playground上尝试):

{"name":"party","month":10,"year":2009}
<nil> 2009
{"category":"Tool","month":10,"year":2009}
<nil>

注意:MonthYear.t时间字段在此处不起作用(它也没有被编组)。如果不需要原始time.Time,您可以将其删除。