doubo82706 2016-11-30 12:21
浏览 70
已采纳

将接口{}强制转换为运行时类型

Here is schematic example what I need:

func decode(data []byte, target interface{}) (interface{}, error) {
    decoded := target.(reflect.TypeOf(target)) // pseudocode
    err := json.Unmarshal(data, &decoded)
    ...

I found several similar questions on SO, but all solutions are about switch by target.(type). This is not the best solution what I look for.

Also I found solution with reflection:

decoded := reflect.ValueOf(target).Convert(reflect.TypeOf(target))
// fmt.Printf("%T", decoded) == reflect.Value

But I couldn't understand how to get struct from reflect.Value to pass it to json.Unmarshal function.

How this decode function will be used?

I have multiple requests in different structures. I can determine what struct I should use to decode request. I have mapping between request type and structure like this map[RequestMethod]interface{}.

Schematic version looks like this:

func hydrate(data []byte) (interface{}, error) {
    var base baseResponse

    if err := json.Unmarshal(data, &base); err != nil {
        return nil, err
    }

    target, ok := methodsMap[Method(base.Method)]

    if !ok {
        return nil, errors.New("Trying to hydrate data with unknown method: " + base.Method)
    }

    decoded, err := decode(data, target) // Expected target type.

Added:

If we pass our target to json.Unmarshal without casting to it type we will obtain map. Example:

func decode(data []byte, target interface{}) (interface{}, error) {
    err := json.Unmarshal(data, &target)
    // fmt.Printf("%T", target) == map[string]interface{} not struct.

Solution

Thanks to @icza we found solution:

func hydrate(data []byte) (interface{}, error) { var base baseResponse

    if err := json.Unmarshal(data, &base); err != nil {
        return nil, err
    }

    target, ok := methodsMap[Method(base.Method)]

    if !ok {
        return nil, errors.New("Trying to hydrate data with unknown method: " + base.Method)
    }

    // Clone request draft struct.
    decoded := reflect.New(reflect.ValueOf(target).Type()).Interface()
    err := decode(data, decoded)
    ...

Related links:

Golang interface{} type misunderstanding

How to copy an interface value in Go?

  • 写回答

1条回答 默认 最新

  • doubaolan2842 2016-11-30 13:49
    关注

    Use the following code to create a copy of the draft struct and unmarshal to it:

    t := reflect.TypeOf(methodsMap[Method(base.Method)])
    pv := reflect.New(t)
    err := json.Unmarshal(p, pv.Interface())
    return pv.Elem().Interface(), err  // pv.Elem() dereferences ptr 
    

    playground example

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 能给我一些人生建议吗
  • ¥15 mac电脑,安装charles后无法正常抓包
  • ¥18 visio打开文件一直显示文件未找到
  • ¥15 请教一下,openwrt如何让同一usb储存设备拔插后设备符号不变?
  • ¥30 使用quartz框架进行分布式任务定时调度,启动了两个实例,但是只有一个实例参与调度,另外一个实例没有参与调度,不知道是为什么?请各位帮助看一下原因!!
  • ¥50 怎么获取Ace Editor中的python代码后怎么调用Skulpt执行代码
  • ¥30 fpga基于dds生成幅值相位频率和波形可调的容易信号发生器。
  • ¥15 R语言shiny包和ncdf4包报错
  • ¥15 origin绘制有显著差异的柱状图和聚类热图
  • ¥20 simulink实现滑模控制和pid控制对比,提现前者优势