dongyan9838
2014-08-07 13:41
浏览 79

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

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!

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

3条回答 默认 最新

  • dongyan5239 2014-08-07 14:09
    已采纳

    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.

    点赞 打赏 评论
  • douxiapi4381 2014-08-07 13:47

    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

    点赞 打赏 评论
  • duanfu3597 2014-08-07 13:52

    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])
    
    点赞 打赏 评论

相关推荐 更多相似问题