在 golang 中使用 json 未知结构的对象有没有更简洁的方法?
Is there a more concise way of using json objects of unknown structure in golang?
当我有一个可靠的休息 api 端点时,return 是一些简单的 json,我可以使用结构来准确定义预期的结构 json结果,但是我必须使用某些端点 return 非常大且复杂的 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")
}
并且以同样的方式我有 GetInt
、GetBool
、GetSlice
、GetJsonObj
、
但如您所见,除了类型断言参数外,所有这些函数在内容上几乎完全相同。有没有一种方法可以通过类型断言参数将所有这些函数有效地简化为一个函数?
这是我目前最好的,作为一个非常简单的例子:https://play.golang.org/p/U9WJ0bIJPp
我无法想象你 compress/extract 能做的远不止这些:
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
当我有一个可靠的休息 api 端点时,return 是一些简单的 json,我可以使用结构来准确定义预期的结构 json结果,但是我必须使用某些端点 return 非常大且复杂的 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")
}
并且以同样的方式我有 GetInt
、GetBool
、GetSlice
、GetJsonObj
、
但如您所见,除了类型断言参数外,所有这些函数在内容上几乎完全相同。有没有一种方法可以通过类型断言参数将所有这些函数有效地简化为一个函数?
这是我目前最好的,作为一个非常简单的例子:https://play.golang.org/p/U9WJ0bIJPp 我无法想象你 compress/extract 能做的远不止这些:
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