将JSON解组为最小类型

时间:2018-02-13 16:58:57

标签: json go unmarshalling

我有一个我要解组的Json字符串。 这是有效的:

jsonString := []byte(`{"my_int": 3, "my_string": null}`)
var data map[string]interface{}
err := json.Unmarshal(jsonString, &data)
if err != nil {
    fmt.Println(err)
}
//avroJson := make(map[string]interface{})
for k, v := range data {
    fmt.Printf("%v, %T\n", k, v)
}

我的问题是:my_int 3的值以float64 的形式返回。

我的问题是:如何使用"最小类型"解析json字符串。以便3将返回int32而不是最大类型3 => float64

假设:我的Json很大,只有原始类型,我想要一个真正的float64的最小值继续显示float64

澄清: A"最小类型"意味着如果3可以同时被视为int32float64,那么"最小类型"将是int32,这是您在运行时获得的确切类型: reflect.TypeOf(3).string()

2 个答案:

答案 0 :(得分:4)

由于您正在解析interface{}地图,golang json.Unmarshal documentation的以下部分属于:

  

要将JSON解组为接口值,Unmarshal会将其中一个存储在接口值中:
  ...
  float64,用于JSON号码   字符串,用于JSON字符串
  ...

因此,要将样本数据解组为所需类型,您应该定义一个包含所需字段/类型映射的结构类型,例如:

type MyType struct {
    MyInt    int     `json:"my_int"`
    MyString *string `json:"my_string"`
}

foo := MyType{}
jsonstr := `{"my_int": 3, "my_string": null}`

err := json.Unmarshal([]byte(jsonstr), &foo)
if err != nil {
    panic(err)
}
// foo => main.MyType{MyInt:3, MyString:(*string)(nil)}

答案 1 :(得分:1)

由于您无法在结构中描述数据,因此您可以选择:

  1. 使用json.Decoder将值解析为所需类型。

  2. 将文档解析为通用接口并对值类型进行后处理。

  3. 选项#1是最灵活的,并且可能被实现为比其他选项更高效,因为解析和转换可以在数据的单次传递中执行。

    选项#2可能更简单,但需要两遍数据。以下是后处理步骤的示例:

    func TransformValueTypes(o map[string]interface{}) {
      for k, v := range o {
        // Convert nil values to *string type.
        if v == interface{}(nil) {
          o[k] = (*string)(nil)
        }
        // Convert numbers to int32 if possible
        if x, isnumber := v.(float64); isnumber {
          if math.Floor(x) == x {
            if x >= math.MinInt32 && x <= math.MaxInt32 {
              o[k] = int32(x)
            }
            // Possibly check for other integer sizes here?
          }
          // Possibly check if float32 is possible here?
        }
        // Check for maps and slices here...
      }
    }
    

    因此,如果您致电TransformValueTypes(data),那么您的类型将如下所示:

    // my_int     -> 3     (int32)
    // my_string  -> <nil> (*string)
    // my_string2 -> "foo" (string)
    // my_float   -> 1.23  (float64)
    

    当然,您的转换函数也可以根据键名应用类型转换逻辑。

    重要的是,请注意,如果您的文档可能具有问题中未提及的其他结构(例如嵌套对象或数组),那么转换函数将需要通过更多值类型检查,递归调用和迭代来解释它们。 / p>