在Go中的嵌入式结构中组合任意JSON对象

时间:2015-04-01 11:43:38

标签: json struct go

我试图通过Go中的嵌入式结构以{{"s":"v1", "t":"v2"}, {"s":"v3", "t":"v4"}, etc}的形式生成JSON对象。

Problem中的所有type Problems []Problem项都提前知道时,一切正常,如下面的func ONE() Playground demo中所示这里。

但是,如果某些K:V对包含空值,我希望避免使用{{a},{},{c}}代替所需的{{a},{c}},如下面的func TWO()和演示

或者,如果在不事先知道是否会添加或省略概率项目的情况下如何随意组合probs := Problems{prob0, prob1, prob2, etc}

package main

import (
    "encoding/json"
    "fmt"
)

type Problem struct {
     S string `json:"s,omitempty"`
     T string `json:"t,omitempty"`
}

 type Problems []Problem

 func main() {
     ONE()
     TWO()
}

 func ONE() {
     prob0 := Problem{S: "s0", T: "t0"}
     prob1 := Problem{S: "s1", T: "t1"}
     prob2 := Problem{S: "s2", T: "t2"}

     probs := Problems{prob0, prob1, probe}

       // fmt.Println(probs) // CORRECT: [{s0 t0} {s1 t1} {s2 t2}]

     b, _ := json.Marshal(probs)
     fmt.Println(string(b))

       // CORRECT: [{"s":"s0","t":"t0"},{"s":"s1","t":"t1"},{"s":"s2","t":"t2"}]``
}

 func TWO() {
     prob0 := Problem{S: "s0", T: "t0"}
     prob1 := Problem{S: "", T: ""} // empty values omited BUT NOT {}
     prob2 := Problem{S: "s2", T: "t2"}

     probs := Problems{prob0, prob1, probe}

       // fmt.Println(probs)
       // GOT:    [{s0 t0} { } {s2 t2}]
       // WANTED: [{s0 t0} {s2 t2}]

     b, _ := json.Marshal(probs)
     fmt.Println(string(b))

       // GOT:    [{"s":"s0","t":"t0"},{},{"s":"s2","t":"t2"}]
       // WANTED: [{"s":"s0","t":"t0"},{"s":"s2","t":"t2"}]
}

3 个答案:

答案 0 :(得分:1)

将元素添加到您编组的数组/切片后,您无法对其进行任何操作。如果元素在数组/切片中,则它将被编组(将包含在JSON输出中)。 json.Marshal()函数怎么能猜出你不想编组哪些元素呢?它不能。

您必须排除您不知道输出内容的元素。在您的情况下,您想要排除空的Problem结构。

最好/最简单的方法是创建一个辅助函数,为您创建[]Problem切片,排除空结构:

func createProbs(ps ...Problem) []Problem {
    // Remove empty Problem structs:
    empty := Problem{}
    for i := len(ps) - 1; i >= 0; i-- {
        if ps[i] == empty {
            ps = append(ps[:i], ps[i+1:]...)
        }
    }
    return ps
}

使用此创建切片是这样的:

probs := createProbs(prob0, prob1, prob2)

Go Playground上尝试修改后的应用程序。

输出修改后的代码(注意缺少空结构):

[{"s":"s0","t":"t0"},{"s":"s1","t":"t1"},{"s":"s2","t":"t2"}]
[{"s":"s0","t":"t0"},{"s":"s2","t":"t2"}]

答案 1 :(得分:0)

您无法轻松实现这一目标。空结构也是一个结构,它将被序列化为{}。即使nil值也会序列化为null

以下代码:     包主要

import (
    "encoding/json"
    "fmt"
)

func main() {
     xs := []interface{}{struct{}{},nil}
     b, _ := json.Marshal(xs)
     fmt.Println(string(b))
}

将产生:

[{},null]

Playground

解决方案是为Problems类型实现json.Marshaller接口以跳过空结构。

答案 2 :(得分:0)

func TWO() {
    prob0 := Problem{S: "s0", T: "t0"}
    prob1 := Problem{S: "", T: ""} // empty values omited BUT NOT "{}"
    prob2 := Problem{S: "s2", T: "t2"}
    probs := Problems{prob0, prob1, prob2}

    for i,v := range probs {
        if v == reflect.Zero(reflect.TypeOf(v)).Interface() {
            probs = append(probs[:i], probs[i+1:]...)
        }
    }

    // fmt.Println(probs)
    // GOT:    [{s0 t0} { } {s2 t2}]
    // WANTED: [{s0 t0} {s2 t2}]
    b, _ := json.Marshal(probs)
    fmt.Println(string(b))
    // GOT:    [{"s":"s0","t":"t0"},{},{"s":"s2","t":"t2"}]
    // WANTED: [{"s":"s0","t":"t0"},{"s":"s2","t":"t2"}]
}

或者,您可以使用反射

这里是游乐场的链接(https://play.golang.org/p/D0pW4xE4uf)。我不确定这是否是最佳答案,但它是一种替代方法