在Go中解码动态字段



我从一个外部API得到一个响应,该API有一个可以有2个值的字段:

{"field": []}

{"field": {"key1": "value", "key2": "value"}}

我将结构设置为

type Object Struct {
Field map[string]string `json:"field,omitempty"`
}

然后调用我自己实现的函数来解码响应

func decode(response *http.Response) (*Object, error) {
var response Object
err := json.NewDecoder(response.Body).Decode(&response)
if err != nil {
return nil, err
}
return &response, nil
}

但这只适用于第二个响应(当字段非空时(。对于第一个响应,我得到了一个错误。

您可以为Field执行自定义封送拆收器类型。示例:

type keys struct {
Key1 string
Key2 string
}
type mytype struct {
EmptySlice bool
Keys       *keys
}
func (m *mytype) UnmarshalJSON(b []byte) error {
if bytes.Equal(b, []byte("[]")) {
m.EmptySlice = true
return nil
}
m.Keys = &keys{}
return json.Unmarshal(b, &m.Keys)
}
type Object struct {
Field mytype `json:"field"`
}
func main() {
input := []string{
`{"field": []}`,
`{"field": {"key1": "value", "key2": "value"}}`,
}
for i, s := range input {
var o Object
err := json.Unmarshal([]byte(s), &o)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%d: %+vn", i+1, o)
}
}

https://go.dev/play/p/OqSKfUXHFyb

您可以使用自定义类型并在该类型上实现UnmarshalJSON接口方法。

例如:

type Field struct {
arr []string
m   map[string]string
}
func (f *Field) UnmarshalJSON(b []byte) error {
var m map[string]string
err := json.Unmarshal(b, &m)
if err == nil {
f.m = m
return nil
}
var arr []string
err = json.Unmarshal(b, &arr)
if err == nil {
f.arr = arr
return nil
}
return fmt.Errorf("type of property not array or map")
}

https://go.dev/play/p/JuFE--hWAjw

最新更新