我可以使用MarshalJSON将任意字段添加到golang中的json编码吗?

时间:2014-04-13 17:25:20

标签: json go

假设我编写了以下代码段。操场上的完整代码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让我觉得这应该是可能的,但我很难弄清楚实施情况。

4 个答案:

答案 0 :(得分:25)

这是一个比我之前的答案更好的答案。

type FakeBook Book

func (b Book) MarshalJSON() ([]byte, error) {
    return json.Marshal(struct {
        FakeBook
        Genre string
    }{
        FakeBook: FakeBook(b),
        Genre:    "Satire",
    })
}

由于匿名结构字段是“合并”的(除了一些额外的考虑因素),我们可以使用它来避免重新映射各个字段。请注意使用FakeBook类型来避免无限递归,否则会发生这种情况。

游乐场:http://play.golang.org/p/21YXhB6OyC

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

如果您有许多任意密钥名称,这可能是一个很好的解决方案。

游乐场:https://play.golang.org/p/Umy9rtx2Ms

答案 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映射中,这些字段将不嵌套显示在输出中。

Go Playground