如何将编码为字符串的浮点数数组反序列化为浮点数数组?

3

我正在尝试解析从Web服务获取的一些JSON数据。我已经简化了下面代码中显示的问题。我的问题是,我能否使代码中的版本(c)工作。

我知道对于单个数字值,通过在json注释中添加选项“,string”,可以使“timestamp”正常工作。但我无法弄清楚如何处理编码为字符串的数字数组,或者是否可以这样做。(请参见代码中列出的示例JSON中的“转换”)

package main

import (
    "encoding/json"
    "fmt"    
)

//version (a)
type JsonData1 struct {
    TimeStamp   uint64          `json:"timestamp,string"`
    Conversions [][2]string     `json:"conversions"`
}

//version (b)
type JsonData2 struct {
    TimeStamp   uint64              `json:"timestamp,string"`
    Conversions [][2]json.Number    `json:"conversions"` 
}

//version (c)
type JsonData3 struct {
    TimeStamp   uint64          `json:"timestamp,string"`
    Conversions [][2]float32    `json:"conversions"` 
}

const incomingJson string = `{"timestamp": "1407178369", "conversions": [["1.021", "2.124"], ["2.432", "3.923"], ["3.234", "5.001"]]}`

func main() {
    var data1 JsonData1
    if err1 := json.Unmarshal([]byte(incomingJson), &data1); err1 != nil {
        fmt.Println("Error unmarshaling with struct JsonData1")
        fmt.Println("--> ", err1.Error())
    } else {
        fmt.Println("Success unmarshaling with struct JsonData1")
        fmt.Println("--> ", data1)
    }

    var data2 JsonData2
    if err2 := json.Unmarshal([]byte(incomingJson), &data2); err2 != nil {
        fmt.Println("Error unmarshaling with struct JsonData2")
        fmt.Println("--> ", err2.Error())
    } else {
        fmt.Println("Success unmarshaling with struct JsonData2")
        fmt.Println("--> ", data2)
    }    

    var data3 JsonData3
    if err3 := json.Unmarshal([]byte(incomingJson), &data3); err3 != nil {
        fmt.Println("Error unmarshaling with struct JsonData3")
        fmt.Println("--> ", err3.Error())
    } else {
        fmt.Println("Success unmarshaling with struct JsonData3")
        fmt.Println("--> ", data3)
    }  
}

如果我编译并运行代码,将会得到以下输出:
Success unmarshaling with struct JsonData1
-->  {1407178369 [[1.021 2.124] [2.432 3.923] [3.234 5.001]]}
Success unmarshaling with struct JsonData2
-->  {1407178369 [[1.021 2.124] [2.432 3.923] [3.234 5.001]]}
Error unmarshaling with struct JsonData3
-->  json: cannot unmarshal string into Go value of type float32

你可以在这里运行代码:http://play.golang.org/p/4TC0IgCI8H 有没有一种方法可以将反序列化转换为结构体版本(c)?感谢您的帮助!
3个回答

5

我知道的最简单的方法是定义一个新类型,然后为其定义UnmarshalJSON

type Conversions [][2]float64

func (c *Conversions) UnmarshalJSON(b []byte) error {
    tmp := [][2]json.Number{}
    if err := json.Unmarshal(b, &tmp); err != nil {
        return err
    }

    *c = make(Conversions, len(tmp))
    for i, a := range tmp {
        var (
            pair [2]float64
            err  error
        )
        pair[0], err = a[0].Float64()
        if err != nil {
            return err
        }
        pair[1], err = a[1].Float64()
        if err != nil {
            return err
        }
        (*c)[i] = pair
    }
    return nil
}

Playground,查看版本(d)。这不是最完美的做法,算法可以改进以使用更少的资源,但你已经有了想法。


1
我最喜欢这个答案,因为它允许我直接使用我定义的结构体进行存储,而无需先定义另一个结构体来临时存储未解组的数据。干得好!谢谢。 - dlb

0

如果你在数字周围加上引号,它们会被视为字符串。实际上,在前两个结构中,你没有任何问题。

如果你想将它们转换为数值类型,请使用正确的方法来做到这一点:parse float

在这里你可以看到如何使用ParseFloat:http://play.golang.org/p/XDuiF0FCQq


0

你不能这样做,因为你将它们作为字符串传递,你最好使用 json.Number 并编写一个函数,例如:

func fval(n json.Number) float32 {
    if f, err := n.Float64(); err == nil {
        return float32(f)
    }
    return 0
}
.....
f := fval(data2.Conversions[0][0])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接