Go Struct JSON 数组数组
Go Struct JSON array of arrays
我在尝试映射来自特定请求响应的某些数据时遇到问题,因为在 seriesLabels 中:有些数据没有 属性 名称(整数,字符串),所以我我对如何映射该数据感到困惑:
这是服务响应:
{
"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:""`
}
我做错了什么?声明结构的正确方法是什么?
问题是 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
之后添加检查以确保数组长度和内容(指针)没有改变。
还有其他 JSON 的 Go 解析库可以让这变得不那么麻烦,比如 gojay。
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}
我在尝试映射来自特定请求响应的某些数据时遇到问题,因为在 seriesLabels 中:有些数据没有 属性 名称(整数,字符串),所以我我对如何映射该数据感到困惑:
这是服务响应:
{
"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:""`
}
我做错了什么?声明结构的正确方法是什么?
问题是 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
之后添加检查以确保数组长度和内容(指针)没有改变。
还有其他 JSON 的 Go 解析库可以让这变得不那么麻烦,比如 gojay。
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}