场景说明:
在go语言开发当中,作为中间转发业务 , 往往会在json反系列过程中使用interface来接受任意类型的值,来实现对数据的透明化 ,以便提高业务拓展性,但这情况在反系列化中可能会遇到精度丢失问题,主要表现为uint64、int64类型json反系列化成interface类类型后精度丢失问题。
比如一个精度丢失的例子:
package main
import (
"encoding/json"
"log"
)
type Info struct {
Mode int
Stu student
}
type student struct {
ID uint64 `json:"id"`
Age int `json:"age"`
Name string `json:"name"`
}
type InfoType struct {
Mode int
Stu interface{}
}
func main(){
//源头json数据
InfoData := Info{
Mode: 1,
Stu: student{
ID: 9223372036854775807,
Age: 21,
Name: "xiaoming",
},
}
data , _ := json.Marshal(InfoData)
//中间转发业务 使用interface 来表示student info
var Info InfoType
json.Unmarshal(data , &Info)
jsonData , _ := json.Marshal(Info.Stu)
//处理中间转发业务发来的Stu信息
var stuInfo student
json.Unmarshal(jsonData , &stuInfo)
log.Printf("stuInfo:%+v" , stuInfo)
}
结果为:
stuInfo:{ID:9223372036854776000 Age:21 Name:xiaoming}
由9223372036854775807转变为了9223372036854776000,但如果值不大时,就不会出现精度问题
解决方式:
1、使用json的useNumber属性
//中间转发业务 使用interface 来表示student info
var Info InfoType
d := json.NewDecoder(bytes.NewReader(data))
d.UseNumber()
_ = d.Decode(&Info)
精度丢失的原因分析:默认情况 ,数值类型(int、int64…)json 反系列化成interface类型时,会转为float64类型。即inut64或者uint64转为float64会存在精度丢失的问题。
解决方案分析:json 反系列过程有一个变量useNumber控制数字类型反系列为interface的类型只要有两种,一个是float64,一个是Number(本质就是string类型—type Number string),使用Number类型,相当于数字型 转为string,就会避免精度丢失问题。
2、使用string表示遇到uint64、int64类型的
**注意:**int64或者uint64并非任何值转float64都是精度丢失,只有超过一定的范围值时,才会出现精度丢失问题