2014-03-12 4 views
35

Ich war Marshaling ein Unmarshalling JSONs mit Golang und wenn ich es mit Zahlenfeldern tun will, wandelt Golan es in Gleitkommazahlen anstelle von langen Zahlen, zum Beispiel.JSON Marshalling mit langen Zahlen in Golang, gibt Gleitkommazahl

Ich habe folgende JSON:

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

Nachdem es Marschall auf eine Karte und Abstellungs wieder auf ein JSON-String erhalte ich:

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

Wie Sie das Feld „ID“ zu sehen ist in Fließkomma-Notation.

Der Code, den ich verwende ist die folgende:

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) 

} 

Er druckt: Karte [ID: 1.2423434e + 07 Name: Fernando] { "Name": "Fernando", "id" : 1.2423434e + 07}

Es scheint zu sein, dass der erste Marshalel auf der Karte das FP generiert. Wie kann ich es zu lange beheben?

Dies ist der Link zu dem Programm in dem Goland Spielplatz: http://play.golang.org/p/RRJ6uU4Uw-

Fer

+2

Sie Marschall nicht in eine 'Karte [string] Schnittstelle {}' aber eine richtige Struktur mit z.B. ein 'int64'-Feld für 'id'. – Volker

Antwort

9

Die JSON standard nicht über longs oder schwimmt, hat es nur Zahlen. Das json Paket wird float64 annehmen, wenn Sie nichts anderes definiert haben (also nur Unmarshal mit einem interface{}).

Was Sie tun sollten, ist eine richtige Struktur zu schaffen (wie Volker erwähnt):

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

Ergebnis:

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

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

Edit:

Falls Sie eine dynamische json Struktur haben und wollen die Vorteile einer Struktur verwenden, können Sie es json.RawMessage mit lösen. Eine Variable vom Typ json.RawMessage speichert die unformatierte JSON-Zeichenfolge, so dass Sie später, wenn Sie wissen, welche Art von Objekt sie enthält, sie in die richtige Struktur entpacken kann. Egal, welche Lösung Sie verwenden, Sie werden in jedem Fall etwas if oder switch Aussage benötigen, wo Sie bestimmen, welche Art von Struktur es ist.

Es ist auch nützlich, wenn Teile der JSON-Daten nur in das andere JSON-Objekt kopiert werden, beispielsweise mit dem id -Wert einer JSON-RPC-Anfrage.

Beispiel einer Containerstruktur mit json.RawMessage und die entsprechenden JSON-Daten:

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

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

Eine modifizierte Version von Ihrem Beispiel auf Spielplatz: http://play.golang.org/p/85s130Sthu

Edit2:

Wenn die Struktur Ihres JSON-Wert wird auf den Namen einer Basis Name/Wert-Paar, können Sie das gleiche mit a:

type Container map[string]json.RawMessage 
+0

Der Kommentar "// Marshal der JSON zu einer Karte" sollte zu "// Marshal der JSON zu einer Struktur" geändert worden sein. – peterSO

+0

@peterSo: Ich habe gerade bemerkt, dass ich die Kommentare verpasst habe. Fixed it "struct" – ANisus

+1

Das Problem y Ich speichere verschiedene JSON-Strukturen, so dass ich nicht wissen, welche de Struktur vor dem Lesen der JSON wäre – Fersca

50

Es gibt Zeiten, wenn Sie nicht definieren können eine Struktur im Voraus, aber immer noch Zahlen erforderlich, um den Marshal-Unmarshal-Prozess unverändert zu durchlaufen.

In diesem Fall können Sie die UseNumber-Methode für json.Decoder verwenden, die bewirkt, dass alle Zahlen als json.Number entmapshaliert werden (was nur die ursprüngliche Zeichenfolgendarstellung der Zahl ist). Dies kann auch nützlich sein, um sehr große Ganzzahlen in JSON zu speichern.

Zum Beispiel:

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

Ergebnis:

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

Schön! Das war, was ich suchte, ich werde versuchen, es zu benutzen und Feedback geben. – Fersca

+0

Großartig, ich hatte Bedenken, dass echte Floats auch in Ganzzahlen umgewandelt werden. Glücklicherweise tut es das nicht: https://play.golang.org/p/TRo0v4yeBO – linqu

+1

@Fersca Das scheint die Antwort zu sein; Wenn du noch da bist, akzeptiere es vielleicht? –