【问题标题】:Is there a more concise way of using json objects of unknown structure in golang?有没有更简洁的方式在golang中使用未知结构的json对象?
【发布时间】:2023-03-12 05:20:01
【问题描述】:

当我有一个可靠的 rest api 端点返回一些简单的 json 时,我可以使用结构来准确定义预期 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

但正如您所见,除了类型断言参数之外,所有这些函数在内容上几乎相同。有没有办法传入类型断言参数来有效地将所有这些函数简化为一个函数?

【问题讨论】:

  • 这被称为“泛型”或“模板”,它们在 Go 中不可用(我希望它是临时的 :-) 但您可能可以生成这些函数。
  • 是的,我知道它是泛型,而 go 没有它们,但有时一些聪明人会想出一些方法来减少重复代码的数量。
  • 我明白了。抱歉,没有这样的方法 :) 例如,因为没有办法“模板化”输出类型。
  • 请注意,Go 中的 getter 写成 without the Get prefix
  • 如何使用反射。那么GetString 可以是Get(Kind.String)

标签: json go type-assertion


【解决方案1】:

这是我目前最好的,作为一个非常简单的例子: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"))
}

但正如 cmets 中提到的,有一个库提供了一种更强大的方法来处理任意 json,https://github.com/bitly/go-simplejson

【讨论】:

猜你喜欢
  • 2020-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-06
  • 2017-02-01
  • 2012-09-12
相关资源
最近更新 更多