106

I need to decode a JSON string with the float number like:

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

I use the Golang code below:

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

When I run it, get the result:

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

I want to know how to decode the JSON string with type convert.

4 Answers 4

236

The answer is considerably less complicated. Just add tell the JSON interpeter it's a string encoded float64 with ,string (note that I only changed the Price definition):

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)
    }
}
Sign up to request clarification or add additional context in comments.

9 Comments

Thank you! I think this is the best solution for my problem. Could you tell me where is the official document about the usage of ",string"?
Note that the leading comma in front of json:",string" is necessary - it won't work without it.
@dustin any idea how to do that other way around? Convert json number to go string? e.g. "N": 1234 to N: "1234"?
Official document: golang.org/pkg/encoding/json/#Marshal The "string" option signals that a field is stored as JSON inside a JSON-encoded string. It applies only to fields of string, floating point, integer, or boolean types. This extra level of encoding is sometimes used when communicating with JavaScript programs
Does anybody know how to accept both number and string?
|
22

Just letting you know that you can do this without Unmarshal and use json.decode. Here is 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)
}

2 Comments

Is there a way to do the reverser? i.e decode a number into a string variable?
@theNoble247 did you find a solution for it? ( reverser)
6

Avoid converting a string to []byte: b := []byte(s). It allocates a new memory space and copy the whole the content into it.

strings.NewReader interface is better. Below is the code from 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)
    }
}

1 Comment

Your answer makes a great point that I quoted. Did I add to it? See stackoverflow.com/a/62740786/12817546
4

Passing a value in quotation marks make that look like string. Change "price":"3460.00" to "price":3460.00 and everything works fine.

If you can't drop the quotations marks you have to parse it by yourself, using 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)
    }
}

3 Comments

Is there a way that not changing the 'Product' struct and implement a decode function or interface to parse the string to float?
@yanunon Yes, you can use a map of type map[string]interface{} for Unmarshal, and parse that into your struct.
@yanunon Or if you want real flexibility, you can write your own Unmarshal, which calls default Unmarshal with a map[string]interface{}, but uses reflect and strconv packages to do the parsing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.