我有一个我要解组的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
可以同时被视为int32
和float64
,那么"最小类型"将是int32
,这是您在运行时获得的确切类型:
reflect.TypeOf(3).string()
答案 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)
由于您无法在结构中描述数据,因此您可以选择:
使用json.Decoder
将值解析为所需类型。
将文档解析为通用接口并对值类型进行后处理。
选项#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>