【问题标题】:Decoding a dynamic field in Go在 Go 中解码动态字段
【发布时间】:2022-01-20 11:18:52
【问题描述】:

我收到来自外部 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 小写时,你确定它适用于第二种情况吗?
  • 这只是粘贴到这里时的一个错字。但我不认为这与解码有任何关系
  • 它与它有关,如果字段未导出(小写),则两种情况下您的解码都将失败
  • Field 定义为interface{} 类型,解组并稍后键入断言

标签: json go decode


【解决方案1】:

您可以为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: %+v\n", i+1, o)
        }
}

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

【讨论】:

    【解决方案2】:

    您可以使用自定义类型并在该类型上实现 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-11
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 2021-04-28
      • 1970-01-01
      • 2020-12-22
      • 2021-08-23
      相关资源
      最近更新 更多