Làm thế nào để giải mã JSON với kiểu chuyển đổi từ chuỗi sang float64 trong Golang?


83

Tôi cần giải mã một chuỗi JSON với số thực như:

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

Tôi sử dụng mã Golang bên dưới:

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

Khi tôi chạy nó, nhận được kết quả:

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

Tôi muốn biết cách giải mã chuỗi JSON với kiểu chuyển đổi.

Câu trả lời:


164

Câu trả lời là ít phức tạp hơn đáng kể. Chỉ cần thêm thông báo cho bộ liên kết JSON rằng đó là một chuỗi float64 được mã hóa với ,string(lưu ý rằng tôi chỉ thay đổi Priceđịnh nghĩa):

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

Cảm ơn bạn! Tôi nghĩ đây là giải pháp tốt nhất cho vấn đề của tôi. Bạn có thể cho tôi biết tài liệu chính thức về việc sử dụng ", string" ở đâu không?
yanunon

3
Lưu ý rằng dấu phẩy đứng trước json:",string"là cần thiết - nó sẽ không hoạt động nếu không có nó.
Darrrrrren

1
@dustin có bất kỳ ý tưởng nào để làm điều đó theo cách khác không? Chuyển đổi số json thành chuỗi? ví dụ như "N": 1234để N: "1234"?
Kamil Dziedzic

Điều đó thực sự tuyệt vời. Ngoại trừ nó không hoạt động trên các lát. Có ai biết cách làm điều này cho [] int không? Chỉ cần thêm cờ ", string" sẽ tạo ra: "không thể bỏ quản lý chuỗi thành giá trị của int" ( play.golang.org/p/aFWSH4lUxv )
Dalibor Filus

@KamilDziedzic bạn đã nhận được giải pháp cho truy vấn của mình chưa?
maverick

12

Chỉ cho bạn biết rằng bạn có thể làm điều này mà không cần Unmarshalsử dụng json.decode. Đây là sân chơi Go

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

4

Chuyển một giá trị trong dấu ngoặc kép làm cho giá trị đó giống như một chuỗi. Thay đổi "price":"3460.00"thành "price":3460.00và mọi thứ hoạt động tốt.

Nếu bạn không thể bỏ dấu ngoặc kép, bạn phải tự mình phân tích cú pháp bằng cách sử dụng 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)
    }
}

Có cách nào không thay đổi cấu trúc 'Sản phẩm' và triển khai chức năng giải mã hoặc giao diện để phân tích cú pháp chuỗi thành float không?
yanunon

1
@yanunon Có, bạn có thể sử dụng một loại bản đồ map[string]interface{}cho Unmarshalvà phân tích cú pháp đó thành cấu trúc của bạn.
Mostafa

@yanunon Hoặc nếu bạn muốn sự linh hoạt thực sự, bạn có thể viết của riêng bạn Unmarshal, nó gọi mặc định Unmarshalbằng map[string]interface{}, nhưng sử dụng reflectstrconvgói để thực hiện phân tích cú pháp.
Mostafa

3

Tránh chuyển đổi một chuỗi [] byte: b := []byte(s). Nó phân bổ một không gian bộ nhớ mới và sao chép toàn bộ nội dung vào đó.

strings.NewReadergiao diện tốt hơn. Dưới đây là mã từ 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)
    }
}

Câu trả lời của bạn tạo nên một điểm tuyệt vời mà tôi đã trích dẫn. Tôi đã thêm vào nó? Xem stackoverflow.com/a/62740786/12817546
Tom L
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.