Wie dekodiere ich JSON mit dem Typ convert von string nach float64 in Golang?

83

Ich muss eine JSON-Zeichenfolge mit der Gleitkommazahl wie folgt dekodieren:

{"name":"Galaxy Nexus", "price":"3460.00"}

Ich benutze den folgenden Golang-Code:

package main

import (
    "encoding/json"
    "fmt"
)

type Product struct {
    Name  string
    Price float64
}

func main() {
    s := `{"name":"Galaxy Nexus", "price":"3460.00"}`
    var pro Product
    err := json.Unmarshal([]byte(s), &pro)
    if err == nil {
        fmt.Printf("%+v\n", pro)
    } else {
        fmt.Println(err)
        fmt.Printf("%+v\n", pro)
    }
}

Wenn ich es ausführe, erhalte ich das Ergebnis:

json: cannot unmarshal string into Go value of type float64
{Name:Galaxy Nexus Price:0}

Ich möchte wissen, wie die JSON-Zeichenfolge mit dem Typ convert dekodiert wird.

Yanunon
quelle

Antworten:

164

Die Antwort ist wesentlich unkomplizierter. Fügen Sie dem JSON-Interpeter einfach hinzu, dass es sich um eine Zeichenfolge handelt, mit der float64 codiert ist ,string(beachten Sie, dass ich nur die PriceDefinition geändert habe ):

package main

import (
    "encoding/json"
    "fmt"
)

type Product struct {
    Name  string
    Price float64 `json:",string"`
}

func main() {
    s := `{"name":"Galaxy Nexus", "price":"3460.00"}`
    var pro Product
    err := json.Unmarshal([]byte(s), &pro)
    if err == nil {
        fmt.Printf("%+v\n", pro)
    } else {
        fmt.Println(err)
        fmt.Printf("%+v\n", pro)
    }
}
Dustin
quelle
Vielen Dank! Ich denke, das ist die beste Lösung für mein Problem. Können Sie mir sagen, wo sich das offizielle Dokument über die Verwendung von ", string" befindet?
Yanunon
3
Beachten Sie, dass das führende Komma vor json:",string"erforderlich ist - ohne dieses Komma funktioniert es nicht.
Darrrrrren
1
@dustin eine Idee, wie man das anders herum macht? JSON-Nummer in String umwandeln? zB "N": 1234zu N: "1234"?
Kamil Dziedzic
Das ist wirklich großartig. Außer es funktioniert nicht auf Scheiben. Kennt jemand einen Weg, wie man das für [] int macht? Durch einfaches Hinzufügen des Flags ", string" wird Folgendes erzeugt: "String kann nicht in den go-Wert von int aufgelöst werden" ( play.golang.org/p/aFWSH4lUxv )
Dalibor Filus
@KamilDziedzic hast du eine Lösung für deine Anfrage bekommen?
Außenseiter
12

Lassen Sie Sie einfach wissen, dass Sie dies ohne Unmarshalund verwenden können json.decode. Hier ist Go Playground

package main

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

type Product struct {
    Name  string `json:"name"`
    Price float64 `json:"price,string"`
}

func main() {
    s := `{"name":"Galaxy Nexus","price":"3460.00"}`
    var pro Product
    err := json.NewDecoder(strings.NewReader(s)).Decode(&pro)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(pro)
}
Salvador Dali
quelle
4

Wenn Sie einen Wert in Anführungszeichen setzen, sieht dieser wie eine Zeichenfolge aus. Wechseln Sie "price":"3460.00"zu "price":3460.00und alles funktioniert gut.

Wenn Sie die Anführungszeichen nicht löschen können, müssen Sie sie selbst analysieren, indem Sie Folgendes verwenden strconv.ParseFloat:

package main

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

type Product struct {
    Name       string
    Price      string
    PriceFloat float64
}

func main() {
    s := `{"name":"Galaxy Nexus", "price":"3460.00"}`
    var pro Product
    err := json.Unmarshal([]byte(s), &pro)
    if err == nil {
        pro.PriceFloat, err = strconv.ParseFloat(pro.Price, 64)
        if err != nil { fmt.Println(err) }
        fmt.Printf("%+v\n", pro)
    } else {
        fmt.Println(err)
        fmt.Printf("%+v\n", pro)
    }
}
Mostafa
quelle
Gibt es eine Möglichkeit, die 'Product'-Struktur nicht zu ändern und eine Decodierungsfunktion oder -schnittstelle zu implementieren, um die Zeichenfolge so zu analysieren, dass sie schwebt?
Yanunon
1
@yanunon Ja, Sie können eine Map vom Typ map[string]interface{}für verwenden Unmarshalund diese in Ihre Struktur analysieren.
Mostafa
@yanunon Oder wenn Sie echte Flexibilität wünschen , können Sie Ihre eigenen schreiben Unmarshal, die standardmäßig Unmarshalmit a aufrufen map[string]interface{}, aber das Parsing verwenden reflectund strconvpaketieren.
Mostafa
3

Vermeiden Sie die Konvertierung eines Strings in [] Byte : b := []byte(s). Es weist einen neuen Speicherplatz zu und kopiert den gesamten Inhalt hinein.

strings.NewReaderSchnittstelle ist besser. Unten ist der Code von godoc:

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "log"
    "strings"
)

func main() {
    const jsonStream = `
    {"Name": "Ed", "Text": "Knock knock."}
    {"Name": "Sam", "Text": "Who's there?"}
    {"Name": "Ed", "Text": "Go fmt."}
    {"Name": "Sam", "Text": "Go fmt who?"}
    {"Name": "Ed", "Text": "Go fmt yourself!"}
`
    type Message struct {
        Name, Text string
    }
    dec := json.NewDecoder(strings.NewReader(jsonStream))
    for {
        var m Message
        if err := dec.Decode(&m); err == io.EOF {
            break
        } else if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("%s: %s\n", m.Name, m.Text)
    }
}
g10guang
quelle
Ihre Antwort macht einen großen Punkt, den ich zitiert habe. Habe ich hinzugefügt? Siehe stackoverflow.com/a/62740786/12817546
Tom L