你不知道的Golang 在json反序列化时interface{}对int64做的特殊处理

最近在项目中遇到一个坑,Go语言在json反序列化时,如果未指定类型,则数字(比如int64)会默认是 float64,这样再次序列化的时候造成了精度丢失。
具体可以看如下代码

 
  1. package main

  2.  
  3. import (

  4. "fmt"

  5.  
  6. jsoniter "github.com/json-iterator/go"

  7. )

  8.  
  9. func main() {

  10. s := "{\"a\":6673221165400540161}"

  11.  
  12. d := make(map[string]interface{})

  13. err := jsoniter.Unmarshal([]byte(s), &d)

  14. if err != nil {

  15. panic(err)

  16. }

  17.  
  18. s2, err := jsoniter.Marshal(d)

  19. if err != nil {

  20. panic(err)

  21. }

  22.  
  23. fmt.Println(string(s2))

  24. }

代码执行结果是:

{“a”:6673221165400540000}

原始数据是:

{“a”:6673221165400540161}

产生了精度丢失。

解决办法

 
  1. package main

  2.  
  3. import (

  4. "fmt"

  5. jsoniter "github.com/json-iterator/go"

  6. "strings"

  7. )

  8.  
  9. func main() {

  10. s := "{\"a\":6673221165400540161}"

  11. decoder := jsoniter.NewDecoder(strings.NewReader(s))

  12. decoder.UseNumber()

  13. d := make(map[string]interface{})

  14. err := decoder.Decode(&d)

  15. if err != nil {

  16. panic(err)

  17. }

  18.  
  19. s2, err := jsoniter.Marshal(d)

  20. if err != nil {

  21. panic(err)

  22. }

  23.  
  24. fmt.Println(string(s2))

  25. }

上面的程序,使用了 func (*Decoder) UseNumber 方法告诉反序列化 json 的数字类型的时候,不要直接转换成 float64,而是转换成 json.Number 类型。

json.Number 内部实现机制:

 
  1. // A Number represents a JSON number literal.

  2. type Number string

  3.  
  4. // String returns the literal text of the number.

  5. func (n Number) String() string { return string(n) }

  6.  
  7. // Float64 returns the number as a float64.

  8. func (n Number) Float64() (float64, error) {

  9. return strconv.ParseFloat(string(n), 64)

  10. }

  11.  
  12. // Int64 returns the number as an int64.

  13. func (n Number) Int64() (int64, error) {

  14. return strconv.ParseInt(string(n), 10, 64)

  15. }

json.Number 本质是字符串,反序列化的时候将 json 的数值先转成 json.Number,其实是一种延迟处理的手段,待后续逻辑需要时候,再把 json.Number 转成 float64 或者 int64。

你可能感兴趣的:(golang,go)