【问题标题】:Go Struct JSON array of arraysGo Struct JSON 数组数组
【发布时间】:2021-10-08 21:48:18
【问题描述】:

我在尝试从特定请求响应映射一些数据时遇到问题,因为在 seriesLabels 内部:有数据没有属性名称 (int,string),所以我很困惑如何映射该数据:

这是服务响应:

{
"data": {
    "seriesLabels": [
        [
            0,
            "(none)"
        ],
        [
            0,
            "Cerveza"
        ],
        [
            0,
            "Cigarros"
        ],
        [
            0,
            "Tecate"
        ],
        [
            0,
            "Cafe"
        ],
        [
            0,
            "Amstel"
        ],
        [
            0,
            "Leche"
        ],
        [
            0,
            "Ultra"
        ],
        [
            0,
            "Coca cola"
        ],
        [
            0,
            "Agua"
        ]
    ]
}
}

我映射该信息的结构是:

type PopularWord struct {
    Data *Data `json:"data"`
}

type Data struct {
    SeriesLabels []*SeriesLabels `json:"seriesLabels"`
}

type SeriesLabels struct {
    value int32  `json:""`
    name  string `json:""`
}

我做错了什么?声明结构的正确方法是什么?

【问题讨论】:

标签: arrays json go struct unmarshalling


【解决方案1】:

seriesLabels是一个JSON数组,它的元素也是JSON数组。

要解析一个 JSON 数组,你可以在 Go 中使用切片:

type Data struct {
    SeriesLabels [][]interface{}
}

测试它:

var pw *PopularWord
if err := json.Unmarshal([]byte(src), &pw); err != nil {
    panic(err)
}
fmt.Println(pw)
for _, sl := range pw.Data.SeriesLabels {
    fmt.Println(sl)
}

输出(在Go Playground 上试试):

&{0xc000120108}
[0 (none)]
[0 Cerveza]
[0 Cigarros]
[0 Tecate]
[0 Cafe]
[0 Amstel]
[0 Leche]
[0 Ultra]
[0 Coca cola]
[0 Agua]

要将内部数组作为结构值,您可以实现自定义解组:

type Data struct {
    SeriesLabels []*SeriesLabels `json:"seriesLabels"`
}

type SeriesLabels struct {
    value int32 
    name  string
}

func (sl *SeriesLabels) UnmarshalJSON(p []byte) error {
    var s []interface{}
    if err := json.Unmarshal(p, &s); err != nil {
        return err
    }
    if len(s) > 0 {
        if f, ok := s[0].(float64); ok {
            sl.value = int32(f)
        }
    }

    if len(s) > 1 {
        if s, ok := s[1].(string); ok {
            sl.name = s
        }
    }
    return nil
}

测试代码一样,输出(在Go Playground上试试这个):

&{0xc0000aa0f0}
&{0 (none)}
&{0 Cerveza}
&{0 Cigarros}
&{0 Tecate}
&{0 Cafe}
&{0 Amstel}
&{0 Leche}
&{0 Ultra}
&{0 Coca cola}
&{0 Agua}

【讨论】:

    【解决方案2】:

    问题是SeriesLabels 在 JSON 中表示为一个数组。如果你想使用encoding/json,你必须实现Unmarshaler接口来解码它(否则它只会接受JSON对象)。

    还好代码很简单:

    func (s *SeriesLabels) UnmarshalJSON(d []byte) error {
        arr := []interface{}{&s.value, &s.name}
        return json.Unmarshal(d, &arr)
    }
    

    请注意,此代码会忽略无效输入(数组太长或类型不正确)。根据您的需要,您可能希望在调用 json.Unmarshal 之后添加检查数组长度和内容(指针)没有改变。

    还有其他用于 Go 的 JSON 解析库使这变得不那么麻烦,例如 gojay

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-08
      • 2017-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-25
      • 2020-08-05
      相关资源
      最近更新 更多