web-dev-qa-db-fra.com

Le démasquage JSON avec des nombres longs donne un nombre à virgule flottante

Je marshalais et démêlais des JSON à l'aide de golang et quand je veux le faire avec des champs numériques, golang le transforme en nombres à virgule flottante au lieu d'utiliser des nombres longs, par exemple.

J'ai le JSON suivant:

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

Après marshal à une carte et unmarshal à nouveau à une chaîne json, j'obtiens:

{
    "id":1.2423434e+07,
    "Name":"Fernando"
}

Comme vous pouvez le voir, le champ "id" Est en notation à virgule flottante.

Le code que j'utilise est le suivant:

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

func main() {

    //Create the Json string
    var b = []byte(`
        {
        "id": 12423434, 
        "Name": "Fernando"
        }
    `)

    //Marshal the json to a map
    var f interface{}
    json.Unmarshal(b, &f)
    m := f.(map[string]interface{})

    //print the map
    fmt.Println(m)

    //unmarshal the map to json
    result,_:= json.Marshal(m)

    //print the json
    os.Stdout.Write(result)

}

Il imprime:

map[id:1.2423434e+07 Name:Fernando]
{"Name":"Fernando","id":1.2423434e+07}

Il semble que le premier marshal de la carte génère le FP. Comment puis-je le réparer longtemps?

Ceci est le lien vers le programme dans la cour de récréation de Goland: http://play.golang.org/p/RRJ6uU4Uw-

48
Fersca

Il y a des moments où vous ne pouvez pas définir une structure à l'avance mais avez toujours besoin que les nombres passent par le processus marshal-unmarshal sans changement.

Dans ce cas, vous pouvez utiliser la méthode UseNumber sur json.Decoder, ce qui entraîne le démarshalage de tous les nombres sous la forme json.Number (qui est juste la représentation de chaîne d'origine du nombre). Cela peut également être utile pour stocker de très grands entiers dans JSON.

Par exemple:

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)
}

Résultat:

decoded to map[string]interface {}{"id":"12423434", "Name":"Fernando"}
encoded to {"Name":"Fernando","id":12423434}
69
rog

Le norme JSON n'a pas de longs ni de flottants, il n'a que des nombres. Le package json supposera float64 lorsque vous n'avez rien défini d'autre (c'est-à-dire, uniquement fourni à Unmarshal avec un interface{}).

Ce que vous devez faire est de créer une structure appropriée (comme l'a mentionné Volker):

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)
}

Résultat:

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

Aire de jeux: http://play.golang.org/p/2R76DYVgMK

Modifier:

Si vous avez une structure json dynamique et souhaitez utiliser les avantages d'une structure, vous pouvez la résoudre en utilisant json.RawMessage. Une variable de type json.RawMessage stockera la chaîne JSON brute afin que plus tard, lorsque vous saurez quel type d'objet elle contient, vous puissiez la démarsaler dans la structure appropriée. Quelle que soit la solution que vous utilisez, vous aurez en tout cas besoin d'une instruction if ou switch pour déterminer de quel type de structure il s'agit.

Il est également utile lorsque des parties des données JSON ne seront copiées que vers un autre objet JSON, comme avec la valeur id- d'une requête JSON RPC.

Exemple de structure de conteneur utilisant json.RawMessage et les données JSON correspondantes:

type Container struct {
    Type string          `json:"type"`
    Data json.RawMessage `json:"data"`
}

var b = []byte(`{"type": "person", "data":{"id": 12423434, "Name": "Fernando"}}`)

Une version modifiée de votre exemple sur Playground: http://play.golang.org/p/85s130Sth

Edit2:

Si la structure de votre valeur JSON est basée sur le nom d'une paire nom/valeur, vous pouvez faire de même avec:

type Container map[string]json.RawMessage
15
ANisus