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条)

报告相同问题?

悬赏问题

  • ¥20 求快手直播间榜单匿名采集ID用户名简单能学会的
  • ¥15 DS18B20内部ADC模数转换器
  • ¥15 做个有关计算的小程序
  • ¥15 MPI读取tif文件无法正常给各进程分配路径
  • ¥15 如何用MATLAB实现以下三个公式(有相互嵌套)
  • ¥30 关于#算法#的问题:运用EViews第九版本进行一系列计量经济学的时间数列数据回归分析预测问题 求各位帮我解答一下
  • ¥15 setInterval 页面闪烁,怎么解决
  • ¥15 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题
  • ¥15 如何用Python爬取各高校教师公开的教育和工作经历