Home > database >  Unmarshalling values in scientific notion to integers in Go
Unmarshalling values in scientific notion to integers in Go

Time:06-09

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:

  1. Declare the Value as json.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.
  2. 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?
}
  1. Declare Value as float64
  • Related