douyi4544 2016-04-26 20:02
浏览 94
已采纳

带有解组json的Golang类型转换/断言问题

package main

import (
    "fmt"
    "encoding/json"
    "reflect"
)

type GeneralConfig map[string]interface{}

var data string = `
{
    "key":"value",
    "important_key":
        {"foo":"bar"}
}`

func main() {
    jsonData := &GeneralConfig{}
    json.Unmarshal([]byte(data), jsonData)

    fmt.Println(reflect.TypeOf(jsonData)) //main.GeneralConfig

    jsonTemp := (*jsonData)["important_key"]
    fmt.Println(reflect.TypeOf(jsonTemp)) //map[string]interface {}

    //newGeneralConfig := GeneralConfig(jsonTemp)
    //cannot convert jsonTemp (type interface {}) to type GeneralConfig:
    //need type assertion

    newGeneralConfig := jsonTemp.(GeneralConfig)
    //fmt.Println(reflect.TypeOf(newGeneralConfig))
    //panic: interface conversion: interface {} is map[string]interface {},
    //not main.GeneralConfig

}

Available at the playground

I understand that I can use a nested struct in lieu of GeneralConfig, but that would require me knowing the exact structure of the payload, ie it wouldn't work for different keys (I would be locked into "important_key").

Is there a golang workaround for when I don't know what the value of "important_key" is? I say golang, because if possible, one could require all "important_keys" to have a constant parent key, which could resolve this issue.

To summarize, given an arbitrary json object, there must be a way that I can traverse its keys, and if a value is a custom type, convert the value to that type. Right now it seems that if I use type conversion, it tells me that the type is interface{} and I need to use type assertion; however, if I use type assertion, it tells me that interface{} is map[string]interface{} not main.GeneralConfig.

  • 写回答

3条回答 默认 最新

  • dougang1605 2016-04-26 20:50
    关注

    I agree the comments about trying to utilise the expected structure of the incoming JSON in order to write well-defined Structs, but I'll attempt to answer the question anyway.

    The thing to take away from what you're seeing printed versus the error messages that you're seeing is that the compiler knows less about the type than the runtime because the runtime can look at the actual value. To bring the compiler up-to-speed we must (i) assert (*jsonData)["important_key"] is a map[string]interface{} -- the compiler only knows it to be an interface{} -- and then (ii) type-cast that to a GeneralConfig type. See:

    package main
    
    import (
        "fmt"
        "encoding/json"
    )
    
    type GeneralConfig map[string]interface{}
    
    func main() {
        jsonStruct := new(GeneralConfig)
        json.Unmarshal([]byte(`{"parent_key": {"foo": "bar"}}`), jsonStruct)
        fmt.Printf("%#v
    ", jsonStruct)
        // => &main.GeneralConfig{"parent_key":map[string]interface {}{"foo":"bar"}}
    
        nestedStruct := (*jsonStruct)["parent_key"]
        fmt.Printf("%#v
    ", nestedStruct)
        // => map[string]interface {}{"foo":"bar"}
        // Whilst this shows the runtime knows its actual type is
        // map[string]interface, the compiler only knows it to be an interface{}.
    
        // First we assert for the compiler that it is indeed a
        // map[string]interface{} we are working with. You can imagine the issues
        // that might arrise if we has passed in `{"parent_key": 123}`.
        mapConfig, ok := nestedStruct.(map[string]interface{})
        if !ok {
            // TODO: Error-handling.
        }
    
        // Now that the compiler can be sure mapConfig is a map[string]interface{}
        // we can type-cast it to GeneralConfig:
        config := GeneralConfig(mapConfig)
        fmt.Printf("%#v
    ", config)
        // => main.GeneralConfig{"foo":"bar"}
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?