In my Go code, I was working to unmarshal a JSON payload we receive from an endpoint. This endpoint encodes large values in scientific notation:
type Test struct {
Key string
Value int32
}
func main() {
data := []byte("{\"Key\": \"derp\", \"Value\": 3.898733e 06}")
var t *Test
err := json.Unmarshal(data, &t)
fmt.Printf("Error: %v\n", err)
fmt.Printf("Data: %v\n", t)
}
The encoded value here is equivalent to 3,898,733 in standard notation. However, this code prints an error:
json: cannot unmarshal number 3.898733e 06 into Go struct field Test.Value of type int32
This makes sense because strconv
also fails to parse this value from a string. However, I can do var i int32 = 3.898733e 06
and that compiles and produces the correct answer.
So, how can I address this error?
CodePudding user response:
The declaration var i int32 = 3.898733e 06
works because the literal in this expression is an untyped constant, and untyped constants are evaluated based on context. In this case, even though it is written as a floating-point number, it is interpreted as an int32 at compile time. This does not happen at runtime.
There are several options to make this work for JSON marshaling:
- Declare the
Value
asjson.Number
. This way you can try parsing it as int64, and if that fails, parse it as float64, and convert to int64 and hope you don't lose precision. - Define a custom type and unmarshal yourself:
type LongInt int32
func (i *LongInt) UnmarshalJSON(data []byte) error {
// Parse data yourself and set the int value
// Maybe use big.Int?
}
- Declare
Value
asfloat64