有没有更简洁的方法在golang中使用未知结构的json对象?

时间:2015-10-23 08:59:14

标签: json go type-assertion

当我有一个可靠的rest api端点返回一些简单的json时,我可以使用一个struct来精确定义预期的json结果的结构,但是我必须使用某些端点来返回非常大且复杂的json结果数据,以及这些结果的结构并不总是已知。

我一直用它来解组:

type JsonObj map[string]interface{}

func (jo JsonObj) GetString(name string) (string, error) {
    if val, exists := jo[name]; exists {
        if v, ok := val.(string); ok {
            return v, nil
        }
        return "", errors.New(name+" is not a string")
    }
    return "", errors.New(name+" property not found")
}

func (jo JsonObj) GetFloat64(name string) (float64, error) {
    if val, exists := jo[name]; exists {
        if v, ok := val.(float64); ok {
            return v, nil
        }
        return 0, errors.New(name+" is not a float64")
    }
    return 0, errors.New(name+" property not found")
}

以同样的方式,我有GetIntGetBoolGetSliceGetJsonObj

但正如您所看到的,除了类型断言参数之外,所有这些函数的内容几乎相同。有没有办法传入类型断言参数,以便将所有这些函数有效地减少到一个函数?

1 个答案:

答案 0 :(得分:0)

这是我现在最好的,作为一个非常简单的例子:https://play.golang.org/p/U9WJ0bIJPp 我无法想象你能够压缩/提取它比这更多:

package main

import (
    "fmt"
    "errors"
)

type T interface{}
type JsonObj map[string]T

func (jo JsonObj) Type(name string, defaultVal T, typeName string, typeAsserter func(val T) (T, bool)) (T, error){
    if val, exists := jo[name]; exists {
        if v, ok := typeAsserter(val); ok {
            return v, nil
        }
        return defaultVal, errors.New(name+" is not of type "+typeName)
    }
    return defaultVal, errors.New(name+" property not found")
}

func (jo JsonObj) String(name string) (string, error) {
    ret, err := jo.Type(name, "", "string", func(val T)(ret T, ok bool){ret, ok = val.(string);return})
    return ret.(string), err
}

func (jo JsonObj) Float64(name string) (float64, error) {
    ret, err := jo.Type(name, 0, "float64", func(val T)(ret T, ok bool){ret, ok = val.(float64);return})
    return ret.(float64), err
}

func (jo JsonObj) Int(name string) (int, error) {
    ret, err := jo.Type(name, 0, "int", func(val T)(ret T, ok bool){if ret, ok = val.(float64); ok {ret = int(ret.(float64))};return})
    return ret.(int), err
}

func (jo JsonObj) Bool(name string) (bool, error) {
    ret, err := jo.Type(name, false, "bool", func(val T)(ret T, ok bool){ret, ok = val.(bool);return})
    return ret.(bool), err
}

func main() {
    jo := JsonObj{
        "aString": "foo",
        "aFloat64": 3.142,
        "anInt": 42.0, //in a json string unmarshalling all numbers are float64 even "int"s
        "aBool": true,

    }
    fmt.Println(jo.String("aString"))
    fmt.Println(jo.Float64("aFloat64"))
    fmt.Println(jo.Int("anInt"))
    fmt.Println(jo.Bool("aBool"))
    fmt.Println(jo.String("missingString"))
    fmt.Println(jo.Bool("anInt"))
}

但正如评论中所提到的,有一个库可以提供更强大的工作方式来处理任意json,https://github.com/bitly/go-simplejson