dongleiwei2182 2018-05-07 17:37
浏览 9

使接口进入结构

I'm a little new to golang and trying to process some websocket data.

I get data in the form of:

type Event struct {
    Event string      `json:"event"`
    Data  interface{} `json:"data"`
}

And the Data field is a json object that I want to process and get into the following struct:

type OrderBook struct {
    Pair      string          `json:"pair"`
    Timestamp string          `json:"timestamp"`
    Broker    string          `json:"broker"`
    Bids      []OrderBookItem `json:"bids"`
    Asks      []OrderBookItem `json:"asks"`
}

type OrderBookItem struct {
    Price  float64
    Amount float64
}

from the websocket function:

....
case "data":
    publish(e.Data) <--- this is where the error occurs
....

which calls:

func publish(data OrderBookResult) {
    log.Println("Publishing trade data...", data)

    o := &OrderBook{}
    o.Pair = "BTCEUR"
    o.Timestamp = data.Timestamp
    o.Broker = "Bitstamp"
    o.Asks = data.Asks
    o.Bids = data.Bids

}

The error in the websocket function I get is the following:

cannot use e.Data (type interface {}) as type OrderBookResult in argument to publish: need type assertion

How can I "cast" the websocket struct into the new struct and reference fields, that are not defined on the websocket struct. I have a node.js background and I haven't gotten my head around the strictness of go yet.

Thx

  • 写回答

1条回答 默认 最新

  • duanmei4362 2018-05-07 20:28
    关注

    As others have noted type assertions would be the answer to solve your immediate error given the interface contains the right type of struct.

    But if your interface comes from JSON parsing, it will likely contain a map[string]interface{} and not a OrderBookResult. See here for why that is the case.

    To solve that please read up on how to create a custom JSON marshaller. For example in this blog. Below I have also included a way of processing a map[string]interface{} to get to your data in the publish function.

    So you can either type assert before you call:

    ....
    case "data":
    
        // Assert that e.Data is in fact a struct of type OrderBookResult
        if dataAsOrderBookResult, ok := e.Data.(OrderBookResult); ok {
            publish(dataAsOrderBookResult)
        } else {
            // handle error etc
            ...
        }
    
    ....
    

    Or change the signature of your publish function and type assert the parameter inside:

    func publish(data interface{}) {
        log.Println("Publishing trade data...", data)
    
        o := &OrderBook{}
        // Type switch
        switch v := data.(type) {
        case OrderBookResult:
            o.Pair = "BTCEUR"
            o.Timestamp = v.Timestamp
            o.Broker = "Bitstamp"
            o.Asks = v.Asks
            o.Bids = v.Bids
        case map[string]interface{}:
            o.Pair = "BTCEUR"
            o.Timestamp = v["Timestamp"].(string)
            o.Broker = "Bitstamp"
            // here again you need to type assert correctly and it may be a map again
            //o.Asks = v["Asks"].(OrderBookItem)
            //o.Bids = v["Bids"].(OrderBookItem)
        default:
            // error handling etc.
            ...
        } 
    ...    
    }
    
    评论

报告相同问题?

悬赏问题

  • ¥15 opencv图像处理,需要四个处理结果图
  • ¥15 无线移动边缘计算系统中的系统模型
  • ¥15 深度学习中的画图问题
  • ¥15 java报错:使用mybatis plus查询一个只返回一条数据的sql,却报错返回了1000多条
  • ¥15 Python报错怎么解决
  • ¥15 simulink如何调用DLL文件
  • ¥15 关于用pyqt6的项目开发该怎么把前段后端和业务层分离
  • ¥30 线性代数的问题,我真的忘了线代的知识了
  • ¥15 有谁能够把华为matebook e 高通骁龙850刷成安卓系统,或者安装安卓系统
  • ¥188 需要修改一个工具,懂得汇编的人来。