代码之家  ›  专栏  ›  技术社区  ›  Laxmi Prasad

Golang中json Marshall和Unmarshall的数字不一致

  •  1
  • Laxmi Prasad  · 技术社区  · 2 年前
    package main
    
    import (
        "encoding/json"
        "fmt"
    )
    
    func t() {
        a := int64(1<<63 - 1)
        fmt.Println(a)
        m := map[string]interface{}{
            "balance": a,
        }
    
        data, _ := json.Marshal(m)
        m1 := make(map[string]interface{})
        err := json.Unmarshal(data, &m1)
        panicIF(err)
        fmt.Println(int64(m1["balance"].(float64)))
    }
    
    func panicIF(err error) {
        if err != nil {
            panic(err)
        }
    }
    

    运行上述代码将打印:

    9223372036854775807
    -9223372036854775808
    

    你能解释一下这个问题吗?我在某处读到,在JSON中,我们不应该使用数字>2^53是数字类型,而应该是字符串类型。

    1 回复  |  直到 2 年前
        1
  •  1
  •   icza    2 年前

    当解组到类型的映射时 map[string]any 这个 encoding/json 软件包将选择 float64 键入以解组数字。

    号码 9223372036854775807 无法由类型的值精确表示 浮动64 ,因此将表示接近它的其他数字,即 9223372036854775808.0 . 当您将此数字转换为 int64 ,因为它超出的有效范围 int64 ,结果显然是另一个结果,在你的例子中,代表的最小值 int64 价值观

    添加一些额外的日志记录语句:

    data, err := json.Marshal(m)
    panicIF(err)
    fmt.Println(string(data))
    m1 := make(map[string]interface{})
    err = json.Unmarshal(data, &m1)
    panicIF(err)
    fmt.Println(m1)
    fmt.Printf("%f\n", m1["balance"].(float64))
    fmt.Println(int64(m1["balance"].(float64)))
    

    这将输出(在 Go Playground ):

    9223372036854775807
    {"balance":9223372036854775807}
    map[balance:9.223372036854776e+18]
    9223372036854775808.000000
    -9223372036854775808