在 Go 中表示此 JSON 的最佳方式?
Best way to represent this JSON in Go?
我正在为 Geckoboard 的 return 数据写入一个端点,它的格式除外:
{
"item": [
{
"value": "274057"
},
[
"38594",
"39957",
"35316",
"35913",
"36668",
"45660",
"41949"
]
]
}
"item"
是一个不同结构的数组。我将如何在 Go 中表示这些数据?
注意:这与我如何解组无关,我需要生成这种格式。
这件事比您想象的要容易。对于休闲 reader,它只是没有很好的记录。我会推荐 ffjson
而不是正常的 json
。它的组成方式使您无需更改库名称以外的语法。
就这么简单:
type User struct {
Id int `json:'id'`
Name string `json:name`
SomeId1 int `json:some_id_1`
SomeId2 int `json:some_id_2`
SomeId3 int `json:some_id_3`
SomeId4 int `json:some_id_4`
}
item := map[string]User{}
for i := 0; i < 10; i++ {
item[strconv.itoa(i)] = User{i, "Username X", 38393, 29384, 12393, 123981}
}
buf, err := ffjson.Marshal(&item)
结构的缺点(即使在 ffjson
中仍然如此)是 reflection
将始终被使用,在您需要高性能的时候,您会浪费很多CPU 个周期。 ffjson
比正常 json
快 2-3 倍,当您将其保留在地图上时。通过这种方式,库可以编译您编组的每个数据结构并重新使用它,而不是不断地检查 data-integrity/structure 和 reflect
。
有一种简单的方法可以创建一些数据结构的值,您知道您想要 generate/duplicate:
的 JSON 输出
获取您要生成的输出,并将其解组为 map[string]interface{}
。您将获得一个映射值,当您编组时将产生您想要的输出。当您解组预期输出时,您可以检查结果映射值以了解您需要创建什么才能获得预期输出。
这也适用于您的情况。这是代码:
var m map[string]interface{}
err := json.Unmarshal([]byte(input), &m)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", m)
res, err := json.MarshalIndent(m, "", " ")
if err != nil {
panic(err)
}
fmt.Println(string(res))
其中 input
是您的 JSON 输入:
const input = `{
"item": [
{
"value": "274057"
},
[
"38594",
"39957",
"35316",
"35913",
"36668",
"45660",
"41949"
]
]
}`
此程序生成与您所需的输出(或输入)相同的输出:
map[item:[map[value:274057] [38594 39957 35316 35913 36668 45660 41949]]]
{
"item": [
{
"value": "274057"
},
[
"38594",
"39957",
"35316",
"35913",
"36668",
"45660",
"41949"
]
]
}
在 Go Playground 上试用完整的应用程序。
正在分析您的未编组映射值:
显然它有一个键"item"
,它的值的类型:
fmt.Printf("%T\n", m["item"]); // Prints []interface{}
所以这是一片。它有 2 个值,它们的类型:
fmt.Printf("%T\n", m["item"].([]interface{})[0]); // map[string]interface{}
fmt.Printf("%T\n", m["item"].([]interface{})[1]); // []interface{}
因此切片包含 2 个值:
- 一张地图(
"value" : "274057"
对)
- 和另一个切片(id 或数字列表)
这是重现相同地图值的 Go 代码:
m := map[string]interface{}{
"item": []interface{}{
map[string]interface{}{"value": "274057"},
[]interface{}{"38594", "39957", "35316", "35913", "36668", "45660", "41949"},
},
}
编组这会产生相同的 JSON 输出。
我正在为 Geckoboard 的 return 数据写入一个端点,它的格式除外:
{
"item": [
{
"value": "274057"
},
[
"38594",
"39957",
"35316",
"35913",
"36668",
"45660",
"41949"
]
]
}
"item"
是一个不同结构的数组。我将如何在 Go 中表示这些数据?
注意:这与我如何解组无关,我需要生成这种格式。
这件事比您想象的要容易。对于休闲 reader,它只是没有很好的记录。我会推荐 ffjson
而不是正常的 json
。它的组成方式使您无需更改库名称以外的语法。
就这么简单:
type User struct {
Id int `json:'id'`
Name string `json:name`
SomeId1 int `json:some_id_1`
SomeId2 int `json:some_id_2`
SomeId3 int `json:some_id_3`
SomeId4 int `json:some_id_4`
}
item := map[string]User{}
for i := 0; i < 10; i++ {
item[strconv.itoa(i)] = User{i, "Username X", 38393, 29384, 12393, 123981}
}
buf, err := ffjson.Marshal(&item)
结构的缺点(即使在 ffjson
中仍然如此)是 reflection
将始终被使用,在您需要高性能的时候,您会浪费很多CPU 个周期。 ffjson
比正常 json
快 2-3 倍,当您将其保留在地图上时。通过这种方式,库可以编译您编组的每个数据结构并重新使用它,而不是不断地检查 data-integrity/structure 和 reflect
。
有一种简单的方法可以创建一些数据结构的值,您知道您想要 generate/duplicate:
的 JSON 输出获取您要生成的输出,并将其解组为 map[string]interface{}
。您将获得一个映射值,当您编组时将产生您想要的输出。当您解组预期输出时,您可以检查结果映射值以了解您需要创建什么才能获得预期输出。
这也适用于您的情况。这是代码:
var m map[string]interface{}
err := json.Unmarshal([]byte(input), &m)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", m)
res, err := json.MarshalIndent(m, "", " ")
if err != nil {
panic(err)
}
fmt.Println(string(res))
其中 input
是您的 JSON 输入:
const input = `{
"item": [
{
"value": "274057"
},
[
"38594",
"39957",
"35316",
"35913",
"36668",
"45660",
"41949"
]
]
}`
此程序生成与您所需的输出(或输入)相同的输出:
map[item:[map[value:274057] [38594 39957 35316 35913 36668 45660 41949]]]
{
"item": [
{
"value": "274057"
},
[
"38594",
"39957",
"35316",
"35913",
"36668",
"45660",
"41949"
]
]
}
在 Go Playground 上试用完整的应用程序。
正在分析您的未编组映射值:
显然它有一个键"item"
,它的值的类型:
fmt.Printf("%T\n", m["item"]); // Prints []interface{}
所以这是一片。它有 2 个值,它们的类型:
fmt.Printf("%T\n", m["item"].([]interface{})[0]); // map[string]interface{}
fmt.Printf("%T\n", m["item"].([]interface{})[1]); // []interface{}
因此切片包含 2 个值:
- 一张地图(
"value" : "274057"
对) - 和另一个切片(id 或数字列表)
这是重现相同地图值的 Go 代码:
m := map[string]interface{}{
"item": []interface{}{
map[string]interface{}{"value": "274057"},
[]interface{}{"38594", "39957", "35316", "35913", "36668", "45660", "41949"},
},
}
编组这会产生相同的 JSON 输出。