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

时间:2017-06-09 23:45:01

标签: go reflection

考虑一下:

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

我是Go的新手,所以我担心这可能不是惯用代码。我想实现somelibrary.DoThing所以如果可能,它通过反射正确地从函数参数中推断出结构类型。这就是我所拥有的:

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

事先不知道结构类型,json.Unmarshal只假设instancemap[string]interface{},所以在调用vfn.Call(...)时我会感到恐慌:

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

是否可以将instance接口转换为正确的类型?换句话说,我可以通过传递字符串(或使用一些反射方法)来键入类型断言,而不是将程序可用的类型作为符号吗?

1 个答案:

答案 0 :(得分:3)

是的,这是可能的。这是您的代码更新:

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()})
}

所做的更改:

  1. structPtr(指针)传递给json.Unmarshal;传递值,您将看不到更改
  2. 在传递给instance时删除json.Unmarshal的地址; there is usually never a good reason to have a pointer to an interface
  3. 致电structPtr
  4. 时,请使用instance代替fn

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