繁体   English   中英

如何编组和解组到具有相同值的不同类型的结构中?

[英]How to marshall and unmarshall into a struct with different types for the same value?

我正在调用一个外部 API,我将它解组为一个结构体。

在响应中,大多数字段都是整数,但由于它是 json,因此有几种边缘情况,它可以返回字符串但仍然是有效/有用的信息: "NaN" , "N/A"

我的结构是这样的:

type Example struct {
  Field1 *int64 `json:"field_1,omitempty"`
  Field2 *int64 `json:"field_2,omitempty"`
  Field3 *int64 `json:"field_3,omitempty"`
}

我们有几个要求:

  • 如果 api 返回 NaN 或 N/AI 应该在 FE 中向我的用户显示错误,所以我想用 null 替换这些值,同时预先“捕获”错误,这就是我选择指针值的原因。

  • 如果没有返回值,则在重新编组时完全省略该值。

为了做到这一点,我试图用 JSON null替换“NaN”值

 b = bytes.Replace(b, []byte("NaN"), []byte("null"), -1) ` 

但它不起作用,因为"null"不等于null ,这是问题 1。

第二个问题是,在重新编组时,omitempty 也不区分 nil、0 和空值。

所以重新编组也失败了。 我知道这是一个正在修复中的“常见”问题,但现在有解决方法吗?

因为如果我为“N/A”和“NaN”传递 nil 并使用 omitempty 它将删除它们。 如果我传递 0 就没有意义(商业明智,因为 0 除了“未初始化”之外还有其他含义),如果我删除 Omitempty,它每次都会对整个结构进行编组(大量不必要的数据),并且无法区分 nil ( NA / NaN ) 和 nil (无值)。

最后一个选择是构建一个自定义类型和 marshall / unmarshaller 像这样:

type JSONint64 struct {
  value *int64
  error string
}

但这需要我每次都检查我的 json 响应中的每个数字,而实际上 NaN 和 N/A 是非常罕见的情况,并在前端增加了“复杂性”。

我假设这是一个常见问题,因为 JSON 是无类型的,这通常是如何解决的?

我会解组map[string]interface{}值,然后使用反射或类型断言来确定值的数据类型。

Unmarshal 将其中之一存储在接口值中:

bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null

像这样:

package main

import (
    "encoding/json"
    "fmt"
)

type Example struct {
    Field1 *int64 `json:"field_1,omitempty"`
    Field2 *int64 `json:"field_2,omitempty"`
    Field3 *int64 `json:"field_3,omitempty"`
}

func typeof(v interface{}) string {
    switch v.(type) {
    case float64:
        return "float64"
    case string:
        return "string"
    default:
        return "unknown"
    }
}

func main() {
    d := []byte(`{"field_1": "n/a", "field_2": 2 }"`)
    e := make(map[string]interface{})
    err := json.Unmarshal(d, &e)
    if err != nil {
        fmt.Printf("%v\n", err)
    }
    fmt.Printf("%+v\n", e)
    example := Example{}
    for k, v := range e {
        switch typeof(v) {
        case "float64":
            val := int64(v.(float64))
            switch k {
            case "field_1":
                example.Field1 = &val
            case "field_2":
                example.Field2 = &val
            case "field_3":
                example.Field3 = &val
            default:
                fmt.Printf("Unexpected field: %v\n", k)
            }

        default:
            // display error
        }
    }
    fmt.Printf("Example field_2: %d\n", *example.Field2)

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM