当编组JSON时,如何内联字段?

huangapple go评论87阅读模式
英文:

How do I inline fields when marshalling JSON?

问题

我有一个名为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方法。

英文:

I have a type MonthYear defined like

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(),
    })
}

I'm including it a lot of different structs like

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

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

How do I inline the MonthYear type so that the resulting JSON does not have any embedded objects?

I want the result to look like { "name": "party", "month": 2, "year": 2017 } and { "category": "art", "month": 3, "year": 2016 } without having to write the MarshalJSON for each of the structs.

答案1

得分: 5

我知道这不是你希望得到的答案,但在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(),
    }
}

然后使用嵌入(匿名字段)而不是常规(命名)字段,以在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,可以将其删除。

英文:

I know this is not the answer you wish to receive, but until inline support is added to the encoding/json package, you may use the following workaround:

Make your MonthYear a struct, e.g.:

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

An optional, constructor function for easy creation:

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

And use embedding (anonymous field) instead of a regular (named) field to get "flattened" / inlined in the JSON representation:

type Event struct {
	Name string `json:&quot;name&quot;`
	MonthYear
}

type Item struct {
	Category string `json:&quot;category&quot;`
	MonthYear
}

As an extra, you'll be able to refer to fields directly like Event.Year or Event.Month which is nice.

Testing it:

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

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

Output (try it on the Go Playground):

{&quot;name&quot;:&quot;party&quot;,&quot;month&quot;:10,&quot;year&quot;:2009}
&lt;nil&gt; 2009
{&quot;category&quot;:&quot;Tool&quot;,&quot;month&quot;:10,&quot;year&quot;:2009}
&lt;nil&gt;

Note: The MonthYear.t time field does not play a role here (it is not marshaled either). You can remove it if the original time.Time is not needed.

huangapple
  • 本文由 发表于 2017年3月29日 02:53:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/43077665.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定