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