简体   繁体   English

go reflection:获取正确的struct类型的接口

[英]go reflection: get correct struct type of interface

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\n", thing)
    })
}

I'm new to Go, so I fear this might not be idiomatic code. 我是Go的新手,所以我担心这可能不是惯用的代码。 I'd like to implement somelibrary.DoThing so it correctly infers the struct type from the function argument via reflection, if it's possible. 我想实现somelibrary.DoThing以便通过反射正确地从函数参数中推断出结构类型,如果可能的话。 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(...) : 事先不知道结构类型,json.Unmarshal只假设instancemap[string]interface{} ,所以在调用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? 是否可以将instance接口转换为正确的类型? 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? 换句话说,我可以通过传递字符串(或使用一些反射方法)而不是将程序可用的类型作为符号来键入类型断言吗?

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 ; structPtr (一个指针)传递给json.Unmarshal ; pass a value and you will not see the changes 传递一个值,您将看不到更改
  2. Remove taking the address of instance when passing to json.Unmarshal ; 传递给json.Unmarshal时删除获取instance的地址; there is usually never a good reason to have a pointer to an interface 通常没有一个很好的理由有一个指向接口的指针
  3. Use structPtr instead of instance when calling fn 在调用fn时使用structPtr而不是instance

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM