在Go中按名称调用Struct及其方法?

nvc*_*nvn 29 go go-reflect

MethodByName()http://golang.org/pkg/reflect/#Value.MethodByName找到了一个函数调用,但它并不是我想要的!(也许是因为我不知道如何使用它...我找不到它的任何例子).我想要的是:

type MyStruct struct {
//some feilds here
} 
func (p *MyStruct) MyMethod { 
    println("My statement."); 
} 

CallFunc("MyStruct", "MyMethod"); 
//print out "My statement." 
Run Code Online (Sandbox Code Playgroud)

所以我想,首先我需要一些类似的东西StructByName(),之后使用它MethodByName(),是吧!?

小智 53

要在对象上调用方法,请先使用reflect.ValueOf.然后按名称查找方法,最后调用found方法.例如:

package main

import "fmt"
import "reflect"

type T struct {}

func (t *T) Foo() {
    fmt.Println("foo")
}

func main() {
    var t T
    reflect.ValueOf(&t).MethodByName("Foo").Call([]reflect.Value{})
}
Run Code Online (Sandbox Code Playgroud)


sny*_*nyh 19

type YourT1 struct {}
func (y YourT1) MethodBar() {
    //do something
}

type YourT2 struct {}
func (y YourT2) MethodFoo(i int, oo string) {
    //do something
}

func Invoke(any interface{}, name string, args... interface{}) {
    inputs := make([]reflect.Value, len(args))
    for i, _ := range args {
        inputs[i] = reflect.ValueOf(args[i])
    }
    reflect.ValueOf(any).MethodByName(name).Call(inputs)
}

func main() {
     Invoke(YourT2{}, "MethodFoo", 10, "abc")
     Invoke(YourT1{}, "MethodBar")
}
Run Code Online (Sandbox Code Playgroud)

真正的代码需要检查方法的输入数字或方法是否有效.您可以参考此http://gowalker.org/reflect#Type

  1. 检查"any"是结构类型
  2. 检查"任何"有"名称"的方法
  3. 检查方法"name"输入参数的数量是否等于args的长度
  4. 实现retreflect.Value.Interface()

小心Ptr类型; 或者您可以使用SomeInterface{}而不是直接使用interface{}来确保这种"任何"类型,如下所示

type Shape interface {
    Area() float64  //some method to ensure any is an Shape type.
}

func Invoke(s Shape, name string, inputs...interface{}) []interface{} {
}
Run Code Online (Sandbox Code Playgroud)

所以这没关系

color := Invoke(Circle{}, "GetColor")[0].(Color)
Run Code Online (Sandbox Code Playgroud)

Invoke(NotAShape{}, "ForBar")
Run Code Online (Sandbox Code Playgroud)

无法编译因为NotAnShape不是Shape.

如果您无法确定在编译时将使用哪种第一种类型,则可以构建一个映射来存储所有可能的类型,如下所示.

map[string]reflect.Value{
    "YourT1" : reflect.ValueOf(YourT1{})
    "YourT2" : reflect.ValueOf(YourT2{})
    "Circle" : reflect.ValueOf(Cirlce{}) // or reflect.ValueOf(&Circle{})
}  
Run Code Online (Sandbox Code Playgroud)