简体   繁体   English

使用Go Reflect调用函数

[英]Calling a function with Go Reflect

I was wondering if it was possible to not know a function name but call it anyway and get values from it. 我想知道是否有可能不知道函数名而是无论如何都要调用它并从中获取值。 This lead me to the reflection package and I got pretty close but I'm not sure about the last step - if there is one. 这使我进入了反射包,我已经接近了,但是我不确定最后一步-如果有的话。 Again please forgive me if I am missing something obvious, this is my first attempt at doing anything in Go other than getting it setup. 同样,如果我遗漏了一些明显的东西,请原谅我,这是我第一次尝试在Go中做任何事情,而不是进行设置。

Of course being a compiled language there is no need to iterate through things to find function names, I know them all, but this is something I want to see if it is possible… I'm playing and learning. 当然,作为一种编译语言,不需要遍历所有内容来查找函数名称,我都知道它们,但这是我想看看是否有可能……我正在学习。

Below is the code. 下面是代码。 What I would really like to do is in the main line extract the values set in ModuleBoot() <“1.0012”, 23> and SomethingBoot() <“1.0000”, 10> but so far all as I can get is structure information. 我真正想做的是在主行中提取在ModuleBoot()<“ 1.0012”,23>和SomethingBoot()<“ 1.0000”,10>中设置的值,但到目前为止,我所能获得的只是结构信息。 Perhaps that's just the way it is but perhaps there is a step or change that can make it go the next step. 也许就是这样,但是也许有一个步骤或变更可以使它迈出下一步。

Hopefully I copied all the relevant code over correctly so it compiles as is: 希望我正确地复制了所有相关代码,以便按原样编译:

// Using: go version go1.9.7 linux/amd64
=======================================
FILE: main.go
=======================================
package main

import (
  "fmt"
  "reflect"
  "playing/modules/core"
)

func main() {

  miType := reflect.TypeOf(core.ModuleInfo{})

  fmt.Println("")

  for i := 0; i < miType.NumMethod(); i++ {
    method := miType.Method(i)
    fmt.Println(method.Name)

    in := make([]reflect.Value, method.Type.NumIn())
    in[0] = reflect.ValueOf(core.ModuleInfo{})
    //fmt.Println("Params in:", method.Type.NumIn(), "Params out:", method.Type.NumOut())

    mi := method.Func.Call(in)
    fmt.Println("mi:", mi)

    fmt.Println("")
  }
}

=======================================
FILE: playing/modules/core/something.go
=======================================
package core

func (mi ModuleInfo) SomethingBoot() ModuleInfo {
  mi.Version = "1.0000"
  mi.Priority = 10
  return mi
}

=======================================
FILE: playing/modules/core/modules.go
=======================================
package core

type ModuleInfo struct {
  Version string
  Priority int
}

func (mi ModuleInfo) ModuleBoot() ModuleInfo {
  mi.Version = "1.0012"
  mi.Priority = 23
  return mi
}

The output I got from this was: 我从中得到的输出是:

Started delve with config "Debug"

SomethingBoot
mi: [<core.ModuleInfo Value>]

ModuleBoot
mi: [<core.ModuleInfo Value>]

delve closed with code 0

To get the return value as a ModuleInfo, get the underlying value of the first return value and type assert that interface value to ModuleInfo: 为了得到返回值作为ModuleInfo,获得潜在价值的第一个返回值和输入断言该接口值ModuleInfo:

// mi has type core.ModuleInfo
mi := method.Func.Call(in)[0].Interface().(core.ModuleInfo)

Run it on the Playground . 在Playground上运行它

You can cut some of the reflect code by type asserting the method to a function with the correct signature and calling that function directly: 您可以通过将方法断言为具有正确签名的函数并直接调用该函数来剪切一些反射代码:

for i := 0; i < miType.NumMethod(); i++ {
    method := miType.Method(i).Func.Interface().(func(core.ModuleInfo) core.ModuleInfo)
    mi := method(core.ModuleInfo{})
    fmt.Println("Version", mi.Version)
    fmt.Println("Priority", mi.Priority)
    fmt.Println("")
}

Run it on the Playground 在操场上运行

Go natively supports functions as values; Go本身支持将功能作为值; you don't need reflection to do this. 您不需要进行反思。

In particular, if you make your two functions top-level functions (not specifically tied to a struct): 特别是,如果您将两个函数设为顶级函数(未专门与结构绑定):

package core
type ModuleInfo struct { ... }
func SomethingBoot() ModuleInfo
func ModuleBoot() ModuleInfo

Then you can write a function that takes a function as a parameter: 然后,您可以编写一个将函数作为参数的函数:

func PrintVersion(func booter() core.ModuleInfo) {
        mi := booter()
        fmt.Printf("version %s\n", mi.Version)
}

And you can just pass the pre-existing functions as parameters: 您只需传递预先存在的函数作为参数即可:

PrintVersion(core.SomethingBoot)
PrintVersion(core.ModuleBoot)

Notice that there aren't parentheses after the function name: you are passing the function itself as a parameter, not calling the function and passing its return value. 请注意,函数名称后没有括号:您将函数本身作为参数传递,而不是调用函数并传递其返回值。

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

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