dougou8458 2017-06-09 23:45
浏览 48
已采纳

反思:获取正确的接口结构类型

Consider this:

type myStruct struct {
    Foo string `json:"foo"`
}

func main() {
    somelibrary.DoThing(func(thing myStruct) {
        // myStruct should contain unmarshaled JSON
        // provided by somelibrary

        fmt.Printf("%v
", thing)
    })
}

I'm new to Go, so I fear this might not be idiomatic code. I'd like to implement somelibrary.DoThing so it correctly infers the struct type from the function argument via reflection, if it's possible. Here's what I have:

const jsonData := []byte{`{"foo": "bar"}`}

func DoThing(fn interface{}) {
    // Get first arg of the function
    firstArg := reflect.TypeOf(fn).In(0)
    structPtr := reflect.New(firstArg)

    // Convert to Interface
    // Note that I can't assert this to .(myStruct) type
    instance := structPtr.Elem().Interface()

    // Unmarshal the JSON
    json.Unmarshal(jsonData, &instance)

    // Call the function
    vfn := reflect.ValueOf(fn)
    vfn.Call([]reflect.Value{reflect.ValueOf(instance)})
}

Without knowing the struct type beforehand, json.Unmarshal just assumes that instance is map[string]interface{}, so I get a panic when calling vfn.Call(...):

panic: reflect: Call using map[string]interface {} as type main.myStruct

Is it possible to convert the instance interface into the correct type? In other words, can I do type type assertion by passing a string (or using some reflection method) instead of having the type available to the program as a symbol?

  • 写回答

1条回答 默认 最新

  • dpr77335 2017-06-09 23:50
    关注

    Yes, this is possible. Here is your code updated:

    func DoThing(fn interface{}) {
        // Get first arg of the function
        firstArg := reflect.TypeOf(fn).In(0)
    
        // Get the PtrTo to the first function parameter
        structPtr := reflect.New(firstArg)
    
        // Convert to Interface
        // Note that I can't assert this to .(myStruct) type
        instance := structPtr.Interface()
    
        // Unmarshal the JSON
        json.Unmarshal(jsonData, instance)
    
        // Call the function
        vfn := reflect.ValueOf(fn)
        vfn.Call([]reflect.Value{structPtr.Elem()})
    }
    

    Changes made:

    1. Pass structPtr (a pointer) to json.Unmarshal; pass a value and you will not see the changes
    2. Remove taking the address of instance when passing to json.Unmarshal; there is usually never a good reason to have a pointer to an interface
    3. Use structPtr instead of instance when calling fn

    https://play.golang.org/p/POmOyQBJYC

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

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器