golang中正在对JSON进行解组



我的程序运行起来遇到了很多麻烦。我想把一些非常简单的东西拆开,但不幸的是,这给我带来了很多问题。

以下是我想要解组的响应:

{"error":[],"result":{"XXBTZUSD":[[1647365820,"39192.0","39192.0","39191.9","39191.9","39191.9","0.18008008",10],[1647365880,"39186.1","39186.1","39172.0","39176.0","39174.4","0.13120077",10]],"last":1647408900}}

我写了这些结构来帮助分解

type Resp struct {
Error   []string        `json:"error"`
Result  Trades          `json:"result"`
}
type Trades struct {
Pair    []OHLC          `json:"XXBTZUSD"`
Last    float64         `json:"last"`
}
type OHLC struct {
Time    float64
Open    string
High    string
Low     string
Close   string
Vwa     string
Volume  string
Count   float64
}

我有一个函数调用,它发出http请求,然后对数据进行解组。无论出于何种原因,当Pair类型为[]OHLC或[]*OHLC时,我的代码甚至会在开始http请求的函数调用和随后的解组之前结束。如果我将Pair类型更改为接口{},那么它就会运行。不过,我想让它与OHLC结构一起工作。以下是完整的代码:

package main
import (
"fmt"
"net/http"
//"strings"
"io/ioutil"
"encoding/json"
)
type Resp struct {
Error   []string        `json:"error"`
Result  Trades          `json:"result"`
}
type Trades struct {
Pair    []OHLC          `json:"XXBTZUSD"`
Last    float64         `json:"last"`
}
type OHLC struct {
TT      float64
Open    string
High    string
Low     string
Close   string
Vwap    string
Volume  string
Count   float64
}
/*func main() {
var data = [...]Trade{
Trade{5, "op", "hi", "lo", "cl", "vw", "vo", 2},
Trade{5, "op", "hi", "lo", "cl", "vw", "vo", 2},
}
}*/

func main() {
fmt.Println("in main");
getOhlc()
}
func getOhlc() {
fmt.Println("in ohlc func")
resp, err := http.Get("https://api.kraken.com/0/public/OHLC?pair=XXBTZUSD");
if err != nil {
fmt.Errorf("error after request")
return;
}
defer resp.Body.Close();
body, err := ioutil.ReadAll(resp.Body);
if err != nil {
fmt.Errorf("error when reading")
return;
}
var jsonData Resp;
err = json.Unmarshal(body, &jsonData);
if err != nil {
fmt.Errorf("error when unmarshalling")
return
}
if(len(jsonData.Error) > 0) {
fmt.Errorf("error");
return;
}

fmt.Println(jsonData);
}

对可能发生的事情有什么想法吗?

"对可能发生的事情有什么想法吗">

"XXBTZUSD"JSON数组中的元素本身就是数组,即"XXBTZUSD"是数组的数组。OHLC类型是一种结构类型。stdlib本身不会将JSON数组解组为Go结构。Go结构可用于解组JSON对象。JSON数组可以解组为Go切片或数组。

如果您只是从json中打印错误,您会清楚地看到这就是问题所在。解组:

json:无法将数组分解为Go struct字段Trades.result.XXBTZUSD类型为主。OHLC

https://go.dev/play/p/D4tjXZVzDI_w


如果要将JSON数组解组为Go结构,则必须让Go结构类型实现json.Unmarshaler接口。

func (o *OHLC) UnmarshalJSON(data []byte) error {
// first unmarshal the array into a slice of raw json
raw := []json.RawMessage{}
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
// create a function that unmarshals each raw json element into a field
unmarshalFields := func(raw []json.RawMessage, fields ...interface{}) error {
if len(raw) != len(fields) {
return errors.New("bad number of elements in json array")
}
for i := range raw {
if err := json.Unmarshal([]byte(raw[i]), fields[i]); err != nil {
return err
}
}
return nil
}
// call the function
return unmarshalFields(
raw,
&o.Time,
&o.Open,
&o.High,
&o.Low,
&o.Close,
&o.Vwa,
&o.Volume,
&o.Count,
)
}

https://go.dev/play/p/fkFKLkaNaSU

您的代码出现了一些问题:

  1. 删除行尾的分号,这是多余的
  2. fmt.Errorf返回错误,而不是打印它,每次检查您的错误并传播它
  3. 我们可以在golang中将数组和字符串转换为结构

为了实现您想要的输出,我们需要首先转换到中间容器,然后转换到我们想要的输出:

package main
import (
"errors"
"fmt"
"log"
"net/http"
//"strings"
"encoding/json"
"io/ioutil"
)
type Resp struct {
Error  []string `json:"error"`
Result Trades   `json:"result"`
}
type IntermediateResp struct {
Error  []string           `json:"error"`
Result IntermediateTrades `json:"result"`
}
type IntermediateTrades struct {
Pair [][]interface{} `json:"XXBTZUSD"`
Last int             `json:"last"`
}
type Trades struct {
Pair []OHLC `json:"result"`
Last int    `json:"last"`
}
type OHLC struct {
TT     float64
Open   string
High   string
Low    string
Close  string
Vwap   string
Volume string
Count  float64
}
/*func main() {
var data = [...]Trade{
Trade{5, "op", "hi", "lo", "cl", "vw", "vo", 2},
Trade{5, "op", "hi", "lo", "cl", "vw", "vo", 2},
}
}*/
func main() {
fmt.Println("in main")
err := getOhlc()
if err != nil {
log.Fatal(err)
}
}
func buildOHLC(l []interface{}) (*OHLC, error) {
if len(l) < 8 {
return nil, errors.New("short list")
}
return &OHLC{
TT:     l[0].(float64),
Open:   l[1].(string),
High:   l[2].(string),
Low:    l[3].(string),
Close:  l[4].(string),
Vwap:   l[5].(string),
Volume: l[6].(string),
Count:  l[7].(float64),
}, nil
}
func convert(r IntermediateResp) (*Resp, error) {
result := &Resp{Error: r.Error, Result: Trades{Pair: make([]OHLC, len(r.Result.Pair)), Last: r.Result.Last}}
for i, v := range r.Result.Pair {
ohlc, err := buildOHLC(v)
if err != nil {
return nil, err
}
result.Result.Pair[i] = *ohlc
}
return result, nil
}
func getOhlc() error {
fmt.Println("in ohlc func")
resp, err := http.Get("https://api.kraken.com/0/public/OHLC?pair=XXBTZUSD")
if err != nil {
return fmt.Errorf("error after request, %v", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
if err != nil {
return fmt.Errorf("error when reading %v", err)
}
var jsonData IntermediateResp
err = json.Unmarshal(body, &jsonData)
if err != nil {
return fmt.Errorf("error when unmarshalling %v", err)
}
if len(jsonData.Error) > 0 {
return fmt.Errorf("error")
}
convertedOhlc, err := convert(jsonData)
if err != nil {
return fmt.Errorf("error when convertedOhlc %v", err)
}
fmt.Println(convertedOhlc)
return nil
}

我们定义了IntermediateResp和IntermediateTrades来进行json的解组,然后将其转换为实际的Resp。

我认为另一种方法是对Trades结构使用自定义的Unmarshal。

最新更新