skip to Main Content

I am working with JSON whose structure I may not always know. Unmarshalling the data into map[string]any hence is the most appropriate for my use case. Now the issue is if there’s any numeric value in the JSON data, json.Unmarshal converts it into float64 which is problematic because I may loose precision if the value is actually an integer. Thus when unmarshalling I want the value to be of type int64 in the map when possible but there doesn’t seem to be an easy to accomplish this. What should be my approach to solve this?

2

Answers


  1. The answer you received in the comments is correct and general, but I will give you a more comprehensive answer with an example
    One possible approach to solving this issue is to define a custom type that implements the json.Unmarshaler interface. This allows you to control the unmarshalling process and handle the JSON numeric values as integers when possible. Below is an example implementation:

    type JSONNumber struct {
        AsInt64 int64
        AsFloat64 float64
        ValidInt bool
    }
    
    func (n *JSONNumber) UnmarshalJSON(data []byte) error {
        err := json.Unmarshal(data, &n.AsFloat64)
        n.ValidInt = err == nil && float64(int64(n.AsFloat64)) == n.AsFloat64
    
        if n.ValidInt {
            n.AsInt64 = int64(n.AsFloat64)
        }
        return nil
    }
    

    With this custom type, you can define your map as map[string]JSONNumber, and when unmarshalling, numeric values will be converted to either int64 or float64, depending on their nature. You can then access the values using map[key].AsInt64 or map[key].AsFloat64.

    Here’s an example of using this approach:

    data := []byte(`{"key1": 10, "key2": 10.5}`)
    
    var result map[string]JSONNumber
    err := json.Unmarshal(data, &result)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Println(result["key1"].AsInt64)    // 10
    fmt.Println(result["key2"].AsFloat64)  // 10.5
    

    In this example, the value of "key1" is unmarshalled as int64, while the value of "key2" is unmarshalled as float64.

    Login or Signup to reply.
  2. A float64 is a 64-bit IEEE 754 double-precision type. The internal representation of this type exactly represents integers in the range -2^53 to 2^53, so you only need be concerned if the integers in your problem domain lie outside this range.

    That is: −9,007,199,254,740,992 to 9,007,199,254,740,992

    You may be trying to solve a non-problem. 🙂

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search