JSON unmarshaling with long numbers gives floating point number

后端 未结 2 1476
栀梦
栀梦 2020-12-24 01:40

I was marshaling and unmarshaling JSONs using golang and when I want to do it with number fields golang transforms it in floating point numbers instead of use long numbers,

相关标签:
2条回答
  • 2020-12-24 02:30

    The JSON standard doesn't have longs or floats, it only has numbers. The json package will assume float64 when you haven't defined anything else (meaning, only provided Unmarshal with an interface{}).

    What you should do is to create a proper struct (as Volker mentioned):

    package main
    
    import (
        "encoding/json"
        "fmt"
        "os"
    )
    
    type Person struct {
        Id   int64  `json:"id"`
        Name string `json:"name"`
    }
    
    func main() {
    
        //Create the Json string
        var b = []byte(`{"id": 12423434, "Name": "Fernando"}`)
    
        //Marshal the json to a proper struct
        var f Person
        json.Unmarshal(b, &f)
    
        //print the person
        fmt.Println(f)
    
        //unmarshal the struct to json
        result, _ := json.Marshal(f)
    
        //print the json
        os.Stdout.Write(result)
    }
    

    Result:

    {12423434 Fernando}
    {"id":12423434,"name":"Fernando"}

    Playground: http://play.golang.org/p/2R76DYVgMK

    Edit:

    In case you have a dynamic json structure and wish to use the benefits of a struct, you can solve it using json.RawMessage. A variable of type json.RawMessage will store the raw JSON string so that you later on, when you know what kind of object it contains, can unmarshal it into the proper struct. No matter what solution you use, you will in any case need some if or switch statement where you determine what type of structure it is.

    It is also useful when parts of the JSON data will only be copied to the another JSON object such as with the id-value of a JSON RPC request.

    Example of container struct using json.RawMessage and the corresponding JSON data:

    type Container struct {
        Type string          `json:"type"`
        Data json.RawMessage `json:"data"`
    }
    
    var b = []byte(`{"type": "person", "data":{"id": 12423434, "Name": "Fernando"}}`)
    

    A modified version of your example on Playground: http://play.golang.org/p/85s130Sthu

    Edit2:

    If the structure of your JSON value is based on the name of a name/value pair, you can do the same with a:

    type Container map[string]json.RawMessage
    
    0 讨论(0)
  • 2020-12-24 02:39

    There are times when you cannot define a struct in advance but still require numbers to pass through the marshal-unmarshal process unchanged.

    In that case you can use the UseNumber method on json.Decoder, which causes all numbers to unmarshal as json.Number (which is just the original string representation of the number). This can also useful for storing very big integers in JSON.

    For example:

    package main
    
    import (
        "strings"
        "encoding/json"
        "fmt"
        "log"
    )
    
    var data = `{
        "id": 12423434, 
        "Name": "Fernando"
    }`
    
    func main() {
        d := json.NewDecoder(strings.NewReader(data))
        d.UseNumber()
        var x interface{}
        if err := d.Decode(&x); err != nil {
            log.Fatal(err)
        }
        fmt.Printf("decoded to %#v\n", x)
        result, err := json.Marshal(x)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("encoded to %s\n", result)
    }
    

    Result:

    decoded to map[string]interface {}{"id":"12423434", "Name":"Fernando"}
    encoded to {"Name":"Fernando","id":12423434}
    
    0 讨论(0)
提交回复
热议问题