2013-08-06 49 views
37

我有這樣的結構:如何不使用Go將一個空的結構編組爲JSON?

type Result struct { 
    Data  MyStruct `json:"data,omitempty"` 
    Status  string `json:"status,omitempty"` 
    Reason  string `json:"reason,omitempty"` 
} 

但即使MYSTRUCT的實例是完全空的(意思是,所有的值都是默認值),它被序列化爲:

"data":{} 

我知道,所述encoding/json文檔指定爲「空」的字段有:

假,0,任何零指針或接口值,任何陣列, 切片,地圖或STR長度爲零的零件

但是沒有考慮具有所有空/默認值的結構。它的所有字段也被標記爲omitempty,但這沒有效果。

我怎樣才能得到JSON包不是 marshal我的領域是一個空的結構?

回答

64

哦!輕鬆修復:「任何零指針。」 - 使結構成爲一個指針。

修復:

type Result struct { 
    Data  *MyStruct `json:"data,omitempty"` 
    Status  string `json:"status,omitempty"` 
    Reason  string `json:"reason,omitempty"` 
} 

通知的*MyStruct - 當我現在創建一個MyStruct,我只是通過引用這樣做:

myStruct := &MyStruct{ /* values */ } 

而現在的 「空」 MyStruct不再封根據需要轉換爲JSON。

4

Data是一個初始化結構,所以它不被認爲是空的,因爲encoding/json只查看立即值,而不是結構中的字段。

不幸的是返回niljson.Marhsler目前不起作用:

func (_ MyStruct) MarshalJSON() ([]byte, error) { 
    if empty { 
     return nil, nil // unexpected end of JSON input 
    } 
    // ... 
} 

你可以給一個Result封送爲好,但它不值得。

正如馬特所說,唯一的選擇是讓Data指針並將值設置爲nil

+1

我不明白爲什麼'encoding/json' **不能**檢查struct的子字段。這不會很有效,是的。但這絕對不是不可能的。 – nemo

+0

@nemo我明白了你的觀點,我改變了措詞。它不這樣做,因爲它不會有效。不過,這可以通過'json.Marshaler'完成。 – Luke

+2

通過在MyStruct本身上實現一個'json.Marshaler',它是**不可能**決定是否是'MyStruct'是empty_。證明:http://play.golang.org/p/UEC8A3JGvx – chakrit

5

正如@chakrit在評論中提到的,您無法通過在MyStruct上實現json.Marshaler來實現此功能,並且在使用它的每個結構上實現自定義JSON編組函數可能會有更多工作。這真的取決於你的使用情況,以是否值得額外的工作或你是否已經準備空結構,以住在你的JSON,但這裏是我用來應用於Result模式:

type Result struct { 
    Data  MyStruct 
    Status  string 
    Reason  string  
} 

func (r Result) MarshalJSON() ([]byte, error) { 
    return json.Marshal(struct { 
     Data  *MyStruct `json:"data,omitempty"` 
     Status string  `json:"status,omitempty"` 
     Reason string  `json:"reason,omitempty"` 
    }{ 
     Data: &r.Data, 
     Status: r.Status, 
     Reason: r.Reason, 
    })   
} 

func (r *Result) UnmarshalJSON(b []byte) error { 
    decoded := new(struct { 
     Data  *MyStruct `json:"data,omitempty"` 
     Status string  `json:"status,omitempty"` 
     Reason string  `json:"reason,omitempty"` 
    }) 
    err := json.Unmarshal(b, decoded) 
    if err == nil { 
     r.Data = decoded.Data 
     r.Status = decoded.Status 
     r.Reason = decoded.Reason 
    } 
    return err 
} 

如果你有有很多領域的巨大結構可能會變得單調乏味,特別是稍後改變結構的實現,但很少重寫整個json包以滿足您的需求(這不是一個好主意),這幾乎是我能想到完成這個任務的唯一方法同時仍然保持非指針MyStruct在那裏。

此外,您不必使用內聯結構,您可以創建具名的結構。儘管我使用LiteIDE代碼完成,所以我更喜歡內聯以避免混亂。

相關問題