给定以下结构:
type Person struct {
Name string `json:"name"`
}
type Employee struct {
*Person
JobRole string `json:"jobRole"`
}
我可以按预期轻松地将 Employee 编码为 JSON:
p := Person{"Bob"}
e := Employee{&p, "Sales"}
output, _ := json.Marshal(e)
fmt.Printf("%s\n", string(output))
输出:
{"name":"Bob","jobRole":"Sales"}
但是当嵌入式结构具有自定义 MarshalJSON()
方法时...
func (p *Person) MarshalJSON() ([]byte,error) {
return json.Marshal(struct{
Name string `json:"name"`
}{
Name: strings.ToUpper(p.Name),
})
}
它完全崩溃了:
p := Person{"Bob"}
e := Employee{&p, "Sales"}
output, _ := json.Marshal(e)
fmt.Printf("%s\n", string(output))
现在的结果是:
{"name":"BOB"}
(注意明显缺少 jobRole
字段)
这很容易预料到...嵌入的 Person
结构实现了正在调用的 MarshalJSON()
函数。
问题是,这不是我想要的。我想要的是:
{"name":"BOB","jobRole":"Sales"}
也就是说,正常编码 Employee
的字段,并遵循 Person
的 MarshalJSON()
方法来编码其字段,并且返回一些整洁的 JSON。
现在我也可以向 Employee
添加一个 MarshalJSON()
方法,但这需要我知道嵌入类型实现了 MarshalJSON()
以及 (a) 复制其逻辑,或 (b) 调用 Person
的 MarshalJSON()
并以某种方式操纵其输出以适合我想要的位置.这两种方法似乎都很草率,而且不是很适合 future (如果某天我无法控制的嵌入式类型添加自定义 MarshalJSON()
方法怎么办?)
这里有没有我没有考虑过的替代方案?
最佳答案
不要将 MarshalJSON
放在 Person
上,因为它被提升为外部类型。而是创建一个 type Name string
并让 Name
实现 MarshalJSON
。然后将Person
改为
type Person struct {
Name Name `json:"name"`
}
示例:https://play.golang.org/p/u96T4C6PaY
更新
为了更普遍地解决这个问题,您将不得不在外部类型上实现 MarshalJSON
。内部类型的方法被提升为外部类型,因此您无法绕过它。您可以让外部类型调用内部类型的 MarshalJSON
,然后将其解码为通用结构,如 map[string]interface{}
并添加您自己的字段。这个例子就是这样做的,但是它有一个副作用,就是改变最终输出字段的顺序
关于json - 使用自定义 MarshalJSON() 方法嵌入结构的惯用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38489776/