Mam taką strukturę:
type Result struct {
Data MyStruct `json:"data,omitempty"`
Status string `json:"status,omitempty"`
Reason string `json:"reason,omitempty"`
}
Ale nawet jeśli wystąpienie MyStruct jest całkowicie puste (co oznacza, że wszystkie wartości są domyślne), jest serializowane jako:
"data":{}
Wiem, że dokumentacja encoding / json określa, że „puste” pola to:
false, 0, dowolny wskaźnik zerowy lub wartość interfejsu oraz dowolna tablica, wycinek, mapa lub ciąg o długości zero
ale bez uwzględnienia struktury ze wszystkimi pustymi / domyślnymi wartościami. Wszystkie jego pola są również oznaczone tagiem omitempty
, ale nie ma to wpływu.
Jak mogę sprawić, aby pakiet JSON nie organizował mojego pola, które jest pustą strukturą?
&MyStruct{ /* values */ }
liczy się to jako wskaźnik zerowy? Wartość nie jest zerowa.Jak @chakrit wspomniano w komentarzu, nie można uzyskać to do pracy poprzez wdrożenie
json.Marshaler
naMyStruct
i wdrożenie funkcji rozrządowej zwyczaj JSON na każdej struktury, które zastosowań może być o wiele więcej pracy. To naprawdę zależy od twojego przypadku użycia, czy jest to warte dodatkowej pracy, czy też jesteś przygotowany do życia z pustymi strukturami w swoim JSON, ale oto wzorzec, którego używam, zastosowany doResult
: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 }
Jeśli masz ogromne struktury z wieloma polami, może to stać się uciążliwe, zwłaszcza późniejsza zmiana implementacji struktury, ale oprócz przepisania całego
json
pakietu do własnych potrzeb (nie jest to dobry pomysł), jest to właściwie jedyny sposób, w jaki mogę wymyślić zrobiono to z jednoczesnym zachowaniem tam, gdzie nie ma wskaźnikaMyStruct
.Nie musisz też używać struktur wbudowanych, możesz tworzyć nazwane. Używam jednak LiteIDE z uzupełnianiem kodu, więc wolę inline, aby uniknąć bałaganu.
źródło
Data
jest zainicjowaną strukturą, więc nie jest uważana za pustą, ponieważencoding/json
patrzy tylko na bezpośrednią wartość, a nie na pola wewnątrz struktury.Niestety powrót
nil
zjson.Marhsler
obecnie nie działa:func (_ MyStruct) MarshalJSON() ([]byte, error) { if empty { return nil, nil // unexpected end of JSON input } // ... }
Mógłbyś też dać
Result
marszałka, ale to nie jest warte wysiłku.Jedyną opcją, jak sugeruje Matt, jest utworzenie
Data
wskaźnika i ustawienie wartości nanil
.źródło
encoding/json
nie mogę sprawdzić pól potomnych struktury. To nie byłoby zbyt wydajne, tak. Ale z pewnością nie jest to niemożliwe.json.Marshaler
indywidualnie dla każdego przypadku.MyStruct
jest pusta poprzez wdrożeniejson.Marshaler
naMyStruct
sobie. Dowód: play.golang.org/p/UEC8A3JGvxjson.Marshaler
na samymResult
typie zawierającym , co mogłoby być bardzo niewygodne.Istnieje znakomita propozycja Golang dla tej funkcji, która jest aktywna od ponad 4 lat, więc w tym momencie można bezpiecznie założyć, że w najbliższym czasie nie trafi ona do standardowej biblioteki. Jak zauważył @Matt, tradycyjnym podejściem jest konwersja struktur na wskaźniki-struktury . Jeśli to podejście jest niewykonalne (lub niepraktyczne), alternatywą jest użycie alternatywnego kodera JSON, który obsługuje pomijanie struktur o zerowej wartości .
Stworzyłem kopię lustrzaną biblioteki Golang json ( clarketm / json ) z dodaną obsługą pomijania struktur o zerowej wartości, gdy
omitempty
tag jest stosowany. Ta biblioteka wykrywa zeroness w podobny sposób, jak popularny koder YAML go-yaml, poprzez rekurencyjne sprawdzanie publicznych pól struktur .na przykład
$ go get -u "github.com/clarketm/json"
import ( "fmt" "github.com/clarketm/json" // drop-in replacement for `encoding/json` ) type Result struct { Data MyStruct `json:"data,omitempty"` Status string `json:"status,omitempty"` Reason string `json:"reason,omitempty"` } j, _ := json.Marshal(&Result{ Status: "204", Reason: "No Content", }) fmt.Println(string(j))
// Note: `data` is omitted from the resultant json. { "status": "204" "reason": "No Content" }
źródło