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

我正在努力为解组以下 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 info

func 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

        }

 

狐的传说
浏览 157回答 2
2回答

白猪掌柜的

您需要一个自定义的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}另请注意,此自定义解组器功能允许您将价格或交易量转换为浮点数,这可能是您想要的。

HUX布斯

虽然您可以通过使用反射来破解自己的方式,或者甚至可以编写自己的解析器,但最有效的方法是实现一个json.Unmarshaler.不过,还有一些问题。您正在将 a 转换json array为struct,而不仅仅是其中的interface{}元素,所以它应该是:Asks []BitfinexOrder和Bids []BitfinexOrder.您需要包装结构BitfinexOrderBook以使其与数据一起工作。它比使用反射简单得多。默认情况下,将 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或重命名错误。这不是这个问题的范围,我认为为了打字,我暂时保留简称。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go