2015-04-01 35 views
3

我試圖通過Go中的嵌入式結構以{{"s":"v1", "t":"v2"}, {"s":"v3", "t":"v4"}, etc}的形式生成JSON對象。在Go的嵌入式結構中編寫任意的JSON對象

它所有的工作了罰款時type Problems []Problem所有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"}] 
} 

回答

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"}] 
+0

是的,我希望有一個'json:「,omitempty」'類型的魔法藥水來完全省略空結構,從而避免了創建半大JSON對象的一次,然後再次處理以刪除空結構。 :)但謝謝你的回答。 – parens 2015-04-01 12:32:56

0

你不能輕易實現這一點。空結構也是一個結構,它將被序列化爲{}。即使nil的值也會被序列化爲null

以下代碼: 包主

import (
    "encoding/json" 
    "fmt" 
) 

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

會產生:

[{},null] 

Playground

的解決方案將是實現json.Marshaller接口​​型跳過空結構。

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)。我不確定這是否是最好的答案,但它是一種替代方法

+0

謝謝,我還不知道probs JSON對象的最終長度以及反射是否會導致任何性能問題。會檢查。 – parens 2015-04-01 12:46:30

+0

就我個人而言,我認爲接受的答案更適合您的情況,但是當您有多種類型的切片時(例如接口類型),反射方法可以很好地工作。下面是一個人爲的例子,其中這種方法適用於各種不同類型的切片,並刪除所有零值元素https://play.golang.org/p/WFkSFYcWos – user3508122 2015-04-01 13:16:34

+0

還有另一部分此應用程序可能有用,謝謝。 – parens 2015-04-02 03:08:43