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 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥30 用arduino开发esp32控制ps2手柄一直报错
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 求chat4.0解答一道线性规划题,用lingo编程运行,第一问要求写出数学模型和lingo语言编程模型,第二问第三问解答就行,我的ddl要到了谁来求了
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题
  • ¥15 Visual Studio问题