不同类型反射的Golang JSON数组:float64 vs int64

Consider this simple example:

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "reflect"
)

var args = `[1, 2.5, "aaa", true, false]`

func main() {
    var x []interface{}
    err := json.Unmarshal([]byte(args), &x)

    if err != nil {
        log.Fatalf("%s", err.Error())
        panic(fmt.Sprintf("%s", err.Error()))
    }

    for _, arg := range x {
        t := reflect.TypeOf(arg).Kind().String()
        v := reflect.ValueOf(arg)

        if t == "int64" {
            fmt.Printf("int64 %v
", v.Int())
        }

        if t == "float64" {
            fmt.Printf("float64 %v
", v.Float())
        }

        if t == "string" {
            fmt.Printf("string %v
", v.String())
        }

        if t == "bool" {
            fmt.Printf("bool %v
", v.Bool())
        }
    }
}

The program outputs:

float64 1
float64 2.5
string aaa
bool true
bool false

As you can see, my input is a valid JSON which represents an array with five items:

- integer
- floating point number
- string
- boolean
- boolean

When I unmarshal the valid JSON string into []interface{} and try to check the types with reflection, the integer value from JSON has a type of float64. Any idea why? Is this expected behaviour?

This is documented behavior of Unmarshal. All numbers are unmarshaled into float64.

To unmarshal JSON into an interface value, Unmarshal stores one of these in the interface value:

  • bool, for JSON booleans
  • float64, for JSON numbers
  • string, for JSON strings
  • []interface{}, for JSON arrays
  • map[string]interface{}, for JSON objects
  • nil for JSON null

This is because JSON does not have integers, every number in JSON is defined to be a 64 bit floating point.

This is the default behaviour of the JSON decoder. You can change it to output json.Number instead by using the UseNumber method.