如何将编码为字符串的浮点数数组解组为浮点数数组?

huangapple go评论84阅读模式
英文:

How to unmarshal an array of string encoded floats to an array of floats?

问题

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

我知道对于单个数字值,可以通过在json注释中添加选项",string"来实现,就像对于"timestamp"所示的那样。但是我无法弄清楚如何或者是否可以对字符串编码的数字数组起作用。 (请参见代码中列出的示例JSON中的"conversions")

package main

import (
    "encoding/json"
    "fmt"    
)

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

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

//版本(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)的解组?谢谢你的帮助!

英文:

I'm trying to unmarshal some json data I get from a web service. I have simplified the problem which is shown in the code below. My question is can I make version (c) in the code work..

I know it works for single number values as shown for "timestamp" by adding the option ",string" to the json annotation. But I can't figure out how or if this works for arrays of string encoded numbers too. (See "conversions" in the example json listed in the code)

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

If i compile and run the code I get this output:

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

You can run the code here: http://play.golang.org/p/4TC0IgCI8H

Is there a way to achieve unmarshaling into struct version (c)? Thanks for your help!

答案1

得分: 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)。这不是最完美的方法,算法可以改进以使用更少的资源,但你可以理解这个思路。

英文:

The easiest way I know to do this is to define a new type and then define UnmarshalJSON for it:

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, see version (d). This is not the most perfect way to do that and the algorithm can be improved to use less resources, but you get the idea.

答案2

得分: 0

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

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

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

英文:

If you put " around the numbers they are considered like string. In fact, in the first two structure you haven't any problem.

If you want to convert them into numeric type, use the correct method to do that: parse float

Here you can see how you can use ParseFloat: http://play.golang.org/p/XDuiF0FCQq

答案3

得分: 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])
英文:

You can't do that since you pass them as strings, your best bet really is using json.Number and write a function like:

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

huangapple
  • 本文由 发表于 2014年8月7日 21:41:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/25184135.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定