灵活类型的JSON解码

时间:2013-10-30 18:53:40

标签: go

我需要以灵活的方式指定用于解码JSON数据的类型,这意味着需要在运行时指定类型。

请考虑以下代码段:http://play.golang.org/p/F-Jy4ufMPz

s := `{"b":[{"x":9},{"x":4}]}`

var a struct {
  B []interface{}
}
err := json.Unmarshal([]byte(s), &a)
if err != nil {
  panic(err)
}

fmt.Println(a)

哪会产生{[map[x:9] map[x:4]]}。我想解码为特定(struct)类型的数组而不是[]interface{},而不是在编译时指定它。

在没有预先创建阵列的情况下,这有可能吗? (退回的项目数量未知)

我现在能想到的唯一方法是稍后再次对返回的地图进行编码,并将它们解码为指定的类型,这会产生不必要的处理开销。

1 个答案:

答案 0 :(得分:5)

如果在编译时没有指定它,你仍然需要在某处指定它。

如果在检索Json数据之前指定,您只需执行一个切换案例,将其解组到您想要的对象。

如果在 Json数据中指定,您可以将“灵活”部分编组为json.RawMessage,以便在确定适合的结构类型后对其进行处理:

package main

import (
    "encoding/json"
    "fmt"
)

var s = `{"type":"structx", "data":{"x":9,"xstring":"This is structX"}}`

type JsonStruct struct {
    Type string
    Data json.RawMessage
}

type StructX struct {
    X       float64
    Xstring string
}

type StructY struct {
    Y bool
}

func main() {
    var a *JsonStruct
    err := json.Unmarshal([]byte(s), &a)
    if err != nil {
        panic(err)
    }

    switch a.Type {
    case "structx":
        // We Unmashal the RawMessage part into a StructX
        var s *StructX
        json.Unmarshal([]byte(a.Data), &s)
        if err != nil {
            panic(err)
        }
        fmt.Println(s)
    case "structy":
        // Do the same but for structY
    }
}

Playground