dshgdhdfcas30210 2015-10-23 08:59
浏览 387
已采纳

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

When I have a reliable rest api endpoint that returns some simple json, I can use a struct to define exactly the structure of the expected json result, but there are certain endpoints I have to use that return very large and complex json result data, and the structure of these results are not always known.

I have been using this to unmarshal into:

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")
}

and in this same way I have GetInt, GetBool, GetSlice, GetJsonObj,

but as you can see all of these functions are virtually identical in content except for the type assertion parameter. is there a way of passing in the type assertion parameter to reduce all these functions effectively to a single function?

  • 写回答

1条回答 默认 最新

  • dongmozhui3805 2015-10-23 10:19
    关注

    This is the best I've got right now, as a very simple example: https://play.golang.org/p/U9WJ0bIJPp I can't imagine you'd be able to compress/extract it much more than this:

    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"))
    }
    

    But as mentioned in the comments there is a library which provides a much more robust means of working with arbitrary json, https://github.com/bitly/go-simplejson

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 R语言卸载之后无法重装,显示电脑存在下载某些较大二进制文件行为,怎么办
  • ¥15 java 的protected权限 ,问题在注释里