目前问题是出现在使用了uint64的雪花算法ID中发生的问题,在解析出数据的时候导致精度丢失。以下demo并不是使用转换为字符串方式解决。
package main
import (
"encoding/json"
"fmt"
)
func main() {
var myjson string
myjson = `{"id":9723275009654785}`
fmt.Println("期望结果:", myjson)
type myjsonStruct struct {
Id uint64 `json:"id"`
}
//定义的结构体以及类型 就可以直接解析 此时就是正确的数值不会超出精度。在你完全掌控的结构内可以自行定义字段和类型。
var myjsonStruct1 myjsonStruct
json.Unmarshal([]byte(myjson), &myjsonStruct1)
fmt.Println(fmt.Sprintf("%+v", myjsonStruct1)) //{Id:9723275009654785}
//将输出错误的精度数值 【不定义具体结构体时将超出精度的时候会出现错误数值】因为interface在解析的时候会自动转换类型为float64 当int64等超出float64的时候就会出现精度丢失 因为float64实际上比int64可用范围小。
var myjsonStruct2 interface{}
json.Unmarshal([]byte(myjson), &myjsonStruct2)
fmt.Println(fmt.Sprintf("%+v", myjsonStruct2)) //map[id:9.723275009654784e+15] 转出结果9,723,275,009,654,784 少了一位
//此时会输出正确的数值【此时不想定义结构体,但是还想保证结果正确考虑这种方式】
var myjsonStruct3 interface{}
JsonDecode(myjson, &myjsonStruct3) //map[id:9723275009654785]
fmt.Println(fmt.Sprintf("%+v", myjsonStruct3))
}
func JsonDecode(data string, v interface{}) error {
d := json.NewDecoder(strings.NewReader(data))
d.UseNumber()
err := d.Decode(v)
if err != nil {
return err
}
return nil
}
总结描述:
1.使用结构体时是正确的结果。因为结构体中类型由明确的定义,此时json.Unmarshal不会统一对数字使用float64类型,就不会存在转换错误的情况
2.使用interface时在出现大数字的情况下例如16位以上的数字可能会出现精度丢失问题。因为此时json.Unmarshal使用了float64
3.使用json.NewDecoder是正确的。为了方便使用上述进行了封装。原理可能是转为字符串实现的。
4.也可以考虑使用json.Number。本质就是一个字符串,只不过是后面你可以自由转换类型
5.自己通过正则将所有数字转为字符串后再json.Unmarshal
目前我需要数字所以选择了简单的处理办法,使用自己封装的JsonDecode方式进行实现。