假设我编写了以下代码段。操场上的完整代码here适用于那些倾向的人。
type Book struct {
Title string
Author string
}
func main() {
ms := Book{"Catch-22", "Joseph Heller"}
out, err := json.MarshalIndent(ms, "", " ")
if err != nil {
log.Fatalln(err)
}
fmt.Println(string(out))
}
此代码完全按照我的预期输出以下内容:
{
"Title": "Catch-22",
"Author": "Joseph Heller"
}
假设我想在JSON输出中添加一个字段,而不将其包含在Book
结构中。也许是一种类型:
{
"Title": "Catch-22",
"Author": "Joseph Heller",
"Genre": "Satire"
}
我可以使用MarshalJSON()
向Marshal()
上的JSON有效负载添加任意字段吗?类似的东西:
func (b *Book) MarshalJSON() ([]byte, error) {
// some code
}
其他answers让我觉得这应该是可能的,但我很难弄清楚实施情况。
答案 0 :(得分:25)
这是一个比我之前的答案更好的答案。
type FakeBook Book
func (b Book) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
FakeBook
Genre string
}{
FakeBook: FakeBook(b),
Genre: "Satire",
})
}
由于匿名结构字段是“合并”的(除了一些额外的考虑因素),我们可以使用它来避免重新映射各个字段。请注意使用FakeBook
类型来避免无限递归,否则会发生这种情况。
答案 1 :(得分:3)
这个问题的一个可能的答案是结构文字(code here),虽然我希望有一些更通用的东西,这不需要重新映射所有结构的字段:
func (b *Book) MarshalJSON() ([]byte, error) {
return json.Marshal(struct{
Title string
Author string
Genre string
} {
Title: b.Title,
Author: b.Author,
Genre: "Satire",
})
}
答案 2 :(得分:1)
编组map
是解决问题的另一种方法。
tmap := make(map[string]interface{})
tmap["struct"] = struct {
StructValue string `json:"struct_value"`
}{
"Value 02",
}
tmap["string"] = "Value 01"
out, err := json.MarshalIndent(tmap, "", " ")
if err != nil {
log.Fatalln(err)
}
fmt.Println(string(out))
这将输出:
{
"string": "Value 01",
"struct": {
"struct_value": "Value 02"
}
}
如果您有许多任意密钥名称,这可能是一个很好的解决方案。
答案 3 :(得分:1)
这是一种处理方法:
type Object struct {
A string
B int
Extra map[string]interface{} `json:"-"`
}
func (o Object) MarshalJSON() ([]byte, error) {
type Object_ Object
b, err := json.Marshal(Object_(o))
if err != nil {
return nil, err
}
if o.Extra == nil || len(o.Extra) == 0 {
return b, nil
}
m, err := json.Marshal(o.Extra)
if err != nil {
return nil, err
}
if len(b) == 2 {
return m, nil
} else {
b[len(b)-1] = ','
return append(b, m[1:]...), nil
}
}
您可以将任何其他字段添加到Extra
映射中,这些字段将不嵌套显示在输出中。