本文共 4908 字,大约阅读时间需要 16 分钟。
先来看一下 :
golang 数据类型和json类型对照关系表:
bool, for JSON booleansfloat64, for JSON numbersstring, for JSON strings[]interface{ }, for JSON arraysmap[string]interface{ }, for JSON objectsnil for JSON null
json中没有int64类型的,反序列化的时候,如果直接用json.Unmarshal 可能会精度丢失
可以参考这篇文章:原理:
解析 JSON 的时候其实是对 JSON 串的遍历,其实所有遍历出来的值都是[]byte类型,然后根据识别目标解析对象字段类型,或者识别[]byte数据的内容转换格式。比如,如果数据被解析到int上,把[]byte转换为int;
如果被解析到interface{}上,就只能通过[]byte的类型来转换了, 而且数字会被统一处理成float64,这个有个问题,就是会丢精度。 而通过Number解析时,值会被直接保存为字符串类型。正确做法:
func DecodeMyStruct(jsonStr string) (*MyStruct, error) { var regular *MyStruct decoder := jsoniter.NewDecoder(strings.NewReader(jsonStr)) //使用UseNumber()可以使得json中的大整数转换时,不会转换成浮点数float64,但是要用decoder不能用json.Marshal decoder.UseNumber() err := decoder.Decode(®ular) if err != nil { return nil, err } return ®ular, nil}
其中 MyStruct是我们需要反序列化的类型,可以是struct,slice, map等等.
如果不知道应该反序列化成啥类型,可以是map[string]interface{}
,用的时候可以配合断言使用,
比如下面一种场景:需要对比两个json反序列化成map[string]interface{}
的结构,
func CompareRecursiveV2(ctx context.Context, filterAttrMap, conditionMap map[string]interface{ }) bool { for conditionKey, conditionValue := range conditionMap { filterValue, filterOk := filterAttrMap[conditionKey] if !filterOk { return false } // 断言判断值interface{}的类型 switch conditionValue.(type) { case json.Number: // !!!!这里不能是int64 filterJson, ok1 := filterValue.(json.Number) conditionJson, ok2 := conditionValue.(json.Number) filter := filterJson.String() condition := conditionJson.String() if !ok1 || !ok2 || filter != condition { return false } case string: filter, ok1 := filterValue.(string) condition, ok2 := conditionValue.(string) if !ok1 || !ok2 || filter != condition { return false } case bool: filter, ok1 := filterValue.(bool) condition, ok2 := conditionValue.(bool) if !ok1 || !ok2 || filter != condition { return false } default: conditionValueMap, ok1 := conditionValue.(map[string]interface{ }) if !ok1 { logs.CtxFatal(ctx, "conf error, only support[int64, string, bool, map]") return false } filterValueMap, ok2 := filterValue.(map[string]interface{ }) if !ok1 || !ok2 { return false } // value类型还是map[string]interface{},递归解析比较 return CompareRecursiveV2(ctx, filterValueMap, conditionValueMap) } } return true}
上面case的第一项不能是 int64, 因为两个比较的map是有json转来的,interface{} 里面数字只有number类型(实际上是string存储的),所以,要case number类型,并且转化成字符串判断两个value是不是一样。
这里和下面情况不一样,下面例子:updateStudent 也是 map[string]interface{}
类型
var student_id int64 = 123456 updateStudent["student_id"]= student_id id, ok := updateStudent["student_id"].(int64) // 可以用int64 if !ok { fmt.print("断言失败, key:stedent_id 不是int64类型") } else { fmt.printf(" key:stedent_id 是int64类型, 并且值为:%d", id) }
补充另外一种两个map[string]interface{}
的比较,这里多了一个regular,也是map[string]interface{}
类型的
map[string]interface{}
,进行比较 比如: { "student_id":"int64", "student_name":"string", "genre":"int64", "status":"int64", "extra_struct":{ "father":"string", "risk_rate":"int64", "dynamic_struct":{ "yuwen_score":"int64", "shuxue_score":"int64" } }}
func CompareRecursive(ctx context.Context, regular, filterAttrMap, conditionMap map[string]interface{ }) bool { for regularKey, regularValue := range regular { filterValue, filterOk := filterAttrMap[regularKey] conditionValue, conditionOk := conditionMap[regularKey] if filterOk && conditionOk { if regularValue == "int64" { filterJson, ok1 := filterValue.(json.Number) conditionJson, ok2 := conditionValue.(json.Number) filter := filterJson.String() condition := conditionJson.String() if !ok1 || !ok2 || filter != condition { return false } } else if regularValue == "string" { filter, ok1 := filterValue.(string) condition, ok2 := conditionValue.(string) if !ok1 || !ok2 || filter != condition { return false } } else if regularValue == "bool" { filter, ok1 := filterValue.(bool) condition, ok2 := conditionValue.(bool) if !ok1 || !ok2 || filter != condition { return false } } else { regularValueMap, ok := regularValue.(map[string]interface{ }) if !ok { logs.CtxFatal(ctx, "%s conf error, support[int64, string, bool, map]", regularKey) return false } filterValueMap, ok1 := filterValue.(map[string]interface{ }) conditionValueMap, ok2 := conditionValue.(map[string]interface{ }) if !ok1 || !ok2 { return false } return CompareRecursive(ctx, regularValueMap, filterValueMap, conditionValueMap) } } else if !filterOk && conditionOk { return false } } return true}
转载地址:http://bikzi.baihongyu.com/