在Go中的嵌入式结构中组合任意JSON对象
I'm trying to generate JSON objects in the form of {{"s":"v1", "t":"v2"}, {"s":"v3", "t":"v4"}, etc}
via embedded structs in Go.
It all works out fine when all Problem
items in type Problems []Problem
are known ahead of time, as can be seen in func ONE()
below and in Playground demo here.
However, if some K:V pairs contain empty values I'd like to avoid getting {{a},{},{c}}
instead of the desired {{a},{c}}
, as in func TWO()
below and in demo.
Or alternatively, how can I compose probs := Problems{prob0, prob1, prob2, etc}
below arbitrarily without knowing ahead of time whether a prob item will be added or omitted?
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"}]
}
我正在尝试以 当提前知道 但是,如果某些K:V对包含空值,我想避免获取 或者,或者,我如何在不提前知道是否会添加或省略一个prob项的情况下,任意编写下面的 {{“ s”:“ v1”的形式生成JSON对象 ,“ t”:“ v2”},{“ s”:“ v3”,“ t”:“ v4”}等 code>通过Go中的嵌入式结构。 p>
type Problems [] Problem code>类型的所有
Problem code>项目时,一切正常 在下面的功能
ONE() code>和 游乐场演示 。 p>
{{a},{},{c}} ,而不是所需的
{{a},{c}} code>,如下面的func
TWO() code>和演示中所示。 p>
probs:=问题{prob0,prob1,prob2等} code>? p >
包main
import(
“ encoding / json”
“ fmt”
)
type问题结构{
S字符串`json:“ s, omitempty“`
T字符串`json:” t,omitempty“`
}
类型问题[]问题
func main(){
ONE()
TWO()
}
func ONE(){
prob0:=问题{S:“ s0”,T:“ t0”} \ n prob1:=问题{S:“ s1”,T:“ t1”}
prob2:=问题{S:“ s2”,T:“ t2”}
probs:=问题{prob0,prob1, probe}
// fmt.Println(probs)//正确:[{s0 t0} {s1 t1} {s2 t2}]
b,_:= json.Marshal(probs)
fmt。 Println(string(b))
//正确:[{“ s”:“ s0”,“ t”:“ t0”},{“ s”:“ s1”,“ t”:“ t1” },{“ s”:“ s2”,“ t”:“ t2”}]``
}
func TWO(){
prob0:=问题{S:“ s0”,T:“ t0“}
prob1:=问题{S:”“,T:”“} //空值被忽略但不是{}
prob2:=问题{S:” s2“,T:” t2“}
probs:=问题{prob0,prob1,探针}
// fmt.Println(probs)
// GOT:[{s0 t0} {} {s2 t2}]
//想要的:[ {s0 t0} {s2 t2}]
b,_:= json.Marshal(probs)
fmt.Println(string(b))
// GOT:[{“ s”:“ s0 “,” t“:” t0“},{},{” s“:” s2“,” t“:” t2“}]
//想要:[{” s“:” s0“,” t “:” t0“},{” s“:” s2“,” t“:” t2“}]
}
code> pre>
div>
Once you add an element to the array/slice which you marshal, there's nothing you can do about it. If an element is in the array/slice, it will be marshalled (will be included in the JSON output). How could the json.Marshal()
function guess which elements you don't want to marshal? It can't.
You have to exclude elements which you don't what to appear in the output. In your case you want to exclude empty Problem
structs.
Best/easiest is to create a helper function which creates the []Problem
slice for you, empty structs excluded:
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
}
Using this creating a slice is like this:
probs := createProbs(prob0, prob1, prob2)
Try your modified application on the Go Playground.
Output of the modified code (notice the empty struct is missing):
[{"s":"s0","t":"t0"},{"s":"s1","t":"t1"},{"s":"s2","t":"t2"}]
[{"s":"s0","t":"t0"},{"s":"s2","t":"t2"}]
You can't achieve this easily. Empty structure is also a structure and it will be serialized as {}
. Even nil
value will be serialized as null
.
The following code: package main
import (
"encoding/json"
"fmt"
)
func main() {
xs := []interface{}{struct{}{},nil}
b, _ := json.Marshal(xs)
fmt.Println(string(b))
}
will produce:
[{},null]
The solution would be to implement json.Marshaller interface for Problems
type to skip empty structures.
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"}]
}
Alternatively, you could use reflection
Here's the link to the playground (https://play.golang.org/p/D0pW4xE4uf). I'm not sure if this is the best answer but it's an alternative approach