在 Go 中序列化混合类型 JSON 数组
Serialize a mixed type JSON array in Go
我想要return一个看起来像这样的结构:
{
results: [
["ooid1", 2.0, "Söme text"],
["ooid2", 1.3, "Åther text"],
]
}
这是一个arrags数组,是字符串,浮点数,unicode字符。
如果是 Python 我将能够:
import json
json.dumps({'results': [["ooid1", 2.0, u"Söme text"], ...])
但是在 Go 中你不能有混合类型的数组(或切片)。
我想过使用这样的结构:
type Row struct {
Ooid string
Score float64
Text rune
}
但我不希望每个都成为字典,我希望它成为一个包含 3 个元素的数组。
使用[]interface{}
type Results struct {
Rows []interface{} `json:"results"`
}
如果您想访问存储在 []interface{}
中的值,则必须使用类型断言
for _, row := range results.Rows {
switch r := row.(type) {
case string:
fmt.Println("string", r)
case float64:
fmt.Println("float64", r)
case int64:
fmt.Println("int64", r)
default:
fmt.Println("not found")
}
}
有些笨拙,但可以
type result [][]interface{}
type results struct {
Results result
}
我们可以通过实现 json.Marshaler 接口来自定义对象的序列化方式。对于我们的特定情况,我们似乎有一片 Row
元素,我们希望将其编码为异构值数组。我们可以通过在 Row
类型上定义一个 MarshalJSON
函数来实现,使用 interface{}
的中间切片来编码混合值。
This example 演示:
package main
import (
"encoding/json"
"fmt"
)
type Row struct {
Ooid string
Score float64
Text string
}
func (r *Row) MarshalJSON() ([]byte, error) {
arr := []interface{}{r.Ooid, r.Score, r.Text}
return json.Marshal(arr)
}
func main() {
rows := []Row{
{"ooid1", 2.0, "Söme text"},
{"ooid2", 1.3, "Åther text"},
}
marshalled, _ := json.Marshal(rows)
fmt.Println(string(marshalled))
}
当然,我们也可能想反过来,从 JSON 字节回到结构。所以我们可以使用类似的 json.Unmarshaler 界面。
func (r *Row) UnmarshalJSON(bs []byte) error {
arr := []interface{}{}
json.Unmarshal(bs, &arr)
// TODO: add error handling here.
r.Ooid = arr[0].(string)
r.Score = arr[1].(float64)
r.Text = arr[2].(string)
return nil
}
这使用了类似的技巧,首先使用 interface{}
的中间切片,使用解组器将值放入这个通用容器中,然后将值放回我们的结构中。
package main
import (
"encoding/json"
"fmt"
)
type Row struct {
Ooid string
Score float64
Text string
}
func (r *Row) UnmarshalJSON(bs []byte) error {
arr := []interface{}{}
json.Unmarshal(bs, &arr)
// TODO: add error handling here.
r.Ooid = arr[0].(string)
r.Score = arr[1].(float64)
r.Text = arr[2].(string)
return nil
}
func main() {
rows := []Row{}
text := `
[
["ooid4", 3.1415, "pi"],
["ooid5", 2.7182, "euler"]
]
`
json.Unmarshal([]byte(text), &rows)
fmt.Println(rows)
}
您可以阅读完整示例 here。
我想要return一个看起来像这样的结构:
{
results: [
["ooid1", 2.0, "Söme text"],
["ooid2", 1.3, "Åther text"],
]
}
这是一个arrags数组,是字符串,浮点数,unicode字符。
如果是 Python 我将能够:
import json
json.dumps({'results': [["ooid1", 2.0, u"Söme text"], ...])
但是在 Go 中你不能有混合类型的数组(或切片)。
我想过使用这样的结构:
type Row struct {
Ooid string
Score float64
Text rune
}
但我不希望每个都成为字典,我希望它成为一个包含 3 个元素的数组。
使用[]interface{}
type Results struct {
Rows []interface{} `json:"results"`
}
如果您想访问存储在 []interface{}
for _, row := range results.Rows {
switch r := row.(type) {
case string:
fmt.Println("string", r)
case float64:
fmt.Println("float64", r)
case int64:
fmt.Println("int64", r)
default:
fmt.Println("not found")
}
}
有些笨拙,但可以
type result [][]interface{}
type results struct {
Results result
}
我们可以通过实现 json.Marshaler 接口来自定义对象的序列化方式。对于我们的特定情况,我们似乎有一片 Row
元素,我们希望将其编码为异构值数组。我们可以通过在 Row
类型上定义一个 MarshalJSON
函数来实现,使用 interface{}
的中间切片来编码混合值。
This example 演示:
package main
import (
"encoding/json"
"fmt"
)
type Row struct {
Ooid string
Score float64
Text string
}
func (r *Row) MarshalJSON() ([]byte, error) {
arr := []interface{}{r.Ooid, r.Score, r.Text}
return json.Marshal(arr)
}
func main() {
rows := []Row{
{"ooid1", 2.0, "Söme text"},
{"ooid2", 1.3, "Åther text"},
}
marshalled, _ := json.Marshal(rows)
fmt.Println(string(marshalled))
}
当然,我们也可能想反过来,从 JSON 字节回到结构。所以我们可以使用类似的 json.Unmarshaler 界面。
func (r *Row) UnmarshalJSON(bs []byte) error {
arr := []interface{}{}
json.Unmarshal(bs, &arr)
// TODO: add error handling here.
r.Ooid = arr[0].(string)
r.Score = arr[1].(float64)
r.Text = arr[2].(string)
return nil
}
这使用了类似的技巧,首先使用 interface{}
的中间切片,使用解组器将值放入这个通用容器中,然后将值放回我们的结构中。
package main
import (
"encoding/json"
"fmt"
)
type Row struct {
Ooid string
Score float64
Text string
}
func (r *Row) UnmarshalJSON(bs []byte) error {
arr := []interface{}{}
json.Unmarshal(bs, &arr)
// TODO: add error handling here.
r.Ooid = arr[0].(string)
r.Score = arr[1].(float64)
r.Text = arr[2].(string)
return nil
}
func main() {
rows := []Row{}
text := `
[
["ooid4", 3.1415, "pi"],
["ooid5", 2.7182, "euler"]
]
`
json.Unmarshal([]byte(text), &rows)
fmt.Println(rows)
}
您可以阅读完整示例 here。