在Go中序列化混合类型的JSON数组

时间:2015-01-18 22:53:34

标签: arrays json go

我想返回一个看起来像这样的结构:

{
    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个元素的数组。

3 个答案:

答案 0 :(得分:8)

我们可以通过实现json.Marshaler接口来自定义对象的序列化方式。对于我们的特定情况,我们似乎有一片Row元素,我们想要编码为异构值数组。我们可以通过在MarshalJSON类型上定义Row函数,使用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

答案 1 :(得分:7)

使用[]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")
    } 
}

答案 2 :(得分:0)

有些笨拙,但你可以

type result [][]interface{}
type results struct {
    Results result
}

工作示例https://play.golang.org/p/IXAzZZ3Dg7