为了账号安全,请及时绑定邮箱和手机立即绑定

在正确的结构中转换 json 而不是使用接口

在正确的结构中转换 json 而不是使用接口

Go
狐的传说 2022-04-26 10:44:25
我正在努力为解组以下 json 创建数据结构:{    "asks": [        ["2.049720", "183.556", 1576323009],        ["2.049750", "555.125", 1576323009],        ["2.049760", "393.580", 1576323008],        ["2.049980", "206.514", 1576322995]    ],    "bids": [        ["2.043800", "20.691", 1576322350],        ["2.039080", "755.396", 1576323007],        ["2.036960", "214.621", 1576323006],        ["2.036930", "700.792", 1576322987]    ]}如果我将以下结构与接口一起使用,则没有问题:type OrderBook struct {    Asks [][]interface{} `json:"asks"`    Bids [][]interface{} `json:"bids"`}但我需要更严格的打字,所以我尝试过:type BitfinexOrderBook struct {    Pair string            `json:"pair"`    Asks [][]BitfinexOrder `json:"asks"`    Bids [][]BitfinexOrder `json:"bids"`}type BitfinexOrder struct {    Price     string    Volume    string    Timestamp time.Time}但不幸的是我没有成功。这是我用于解析 Kraken API 以检索订单簿的代码:// loadKrakenOrderBook is delegated to load the data related to pairs infofunc loadKrakenOrderBook(data []byte) (datastructure.BitfinexOrderBook, error) {    var err error    // Creating the maps for the JSON data    m := map[string]interface{}{}    var orderbook datastructure.BitfinexOrderBook    // Parsing/Unmarshalling JSON    err = json.Unmarshal(data, &m)    if err != nil {        zap.S().Debugw("Error unmarshalling data: " + err.Error())        return orderbook, err    }    a := reflect.ValueOf(m["result"])    if a.Kind() == reflect.Map {        key := a.MapKeys()[0]        log.Println("KEY: ", key)        strct := a.MapIndex(key)        log.Println("MAP: ", strct)        m, _ := strct.Interface().(map[string]interface{})        log.Println("M: ", m)        data, err := json.Marshal(m)        if err != nil {            zap.S().Warnw("Panic on key: ", key.String(), " ERR: "+err.Error())            return orderbook, err        } 
查看完整描述

2 回答

?
白猪掌柜的

TA贡献1893条经验 获得超10个赞

您需要一个自定义的Unmarshaler. 这里是。


请注意,BitfinexOrderBook定义与您的定义略有不同。里面有一个错误。


// BitfinexOrderBook is a book of orders.

type BitfinexOrderBook struct {

    Asks []BitfinexOrder `json:"asks"`

    Bids []BitfinexOrder `json:"bids"`

}


// BitfinexOrder is a bitfinex order.

type BitfinexOrder struct {

    Price     string

    Volume    string

    Timestamp time.Time

}


// UnmarshalJSON decode a BifinexOrder.

func (b *BitfinexOrder) UnmarshalJSON(data []byte) error {

    var packedData []json.Number

    err := json.Unmarshal(data, &packedData)

    if err != nil {

        return err

    }

    b.Price = packedData[0].String()

    b.Volume = packedData[1].String()

    t, err := packedData[2].Int64()

    if err != nil {

        return err

    }

    b.Timestamp = time.Unix(t, 0)

    return nil

}

另请注意,此自定义解组器功能允许您将价格或交易量转换为浮点数,这可能是您想要的。


查看完整回答
反对 回复 2022-04-26
?
HUX布斯

TA贡献1876条经验 获得超6个赞

虽然您可以通过使用反射来破解自己的方式,或者甚至可以编写自己的解析器,但最有效的方法是实现一个json.Unmarshaler.

不过,还有一些问题。

  1. 您正在将 a 转换json arraystruct,而不仅仅是其中的interface{}元素,所以它应该是:Asks []BitfinexOrderBids []BitfinexOrder.

  2. 您需要包装结构BitfinexOrderBook以使其与数据一起工作。它比使用反射简单得多。

  3. 默认情况下,将 ajson.Unmarshal解组json number为 float64,这在解析时不是一件好事timestamp。您可以使用json.NewDecoder来获取解码器,然后使用Decoder.UseNumber来强制使用字符串。

例如,

func (bo *BitfinexOrder) UnmarshalJSON(data []byte) error {

    dec := json.NewDecoder(bytes.NewReader(data))

    dec.UseNumber()


    var x []interface{}

    err := dec.Decode(&x)

    if err != nil {

        return errParse(err.Error())

    }


    if len(x) != 3 {

        return errParse("length is not 3")

    }


    price, ok := x[0].(string)

    if !ok {

        return errParse("price is not string")

    }


    volume, ok := x[1].(string)

    if !ok {

        return errParse("volume is not string")

    }


    number, ok := x[2].(json.Number)

    if !ok {

        return errParse("timestamp is not number")

    }

    tint64, err := strconv.ParseInt(string(number), 10, 64)

    if err != nil {

        return errParse(fmt.Sprintf("parsing timestamp: %s", err))

    }


    *bo = BitfinexOrder{

        Price:     price,

        Volume:    volume,

        Timestamp: time.Unix(tint64, 0),

    }

    return nil

}

和 main func(包装结构):


func main() {

    x := struct {

        Result struct{ LINKUSD BitfinexOrderBook }

    }{}

    err := json.Unmarshal(data, &x)

    if err != nil {

        log.Fatalln(err)

    }


    bob := x.Result.LINKUSD

    fmt.Println(bob)

}

游乐场链接: https: //play.golang.org/p/pC124F-3M_S。


注意:操场链接使用辅助函数来创建错误。有些人可能会争辩说最好命名帮助函数NewErrInvalidBitfinexOrder或重命名错误。这不是这个问题的范围,我认为为了打字,我暂时保留简称。


查看完整回答
反对 回复 2022-04-26
  • 2 回答
  • 0 关注
  • 133 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号