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)
}
}
Running above code will print:
9223372036854775807
-9223372036854775808
Can you please explain the issue? I read somewhere that in JSON we should not use numbers > 2^53 with number type, rather it should be string type.
CodePudding user response:
When unmarshaling into a map of type map[string]any
, the encoding/json
package will choose float64
type to unmarshal numbers.
The number 9223372036854775807
cannot be represented precisely by a value of type float64
, so some other number close to it will be represented, here namely 9223372036854775808.0
. When you convert this number to int64
, since it is outside of the valid range of int64
, the result will obviously be something else, in your case the minimum of the representable int64
values.
Add some extra logging statements:
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)))
This will output (try it on the Go Playground):
9223372036854775807
{"balance":9223372036854775807}
map[balance:9.223372036854776e 18]
9223372036854775808.000000
-9223372036854775808