我在http://golang.org/pkg/reflect/#Value.MethodByName找到了一个函数调用MethodByName()
,但这并不是我想要的! (也许是因为我不知道如何使用它...我找不到它的任何例子)。我想要的是:
type MyStruct struct {
//some feilds here
}
func (p *MyStruct) MyMethod {
println("My statement.");
}
CallFunc("MyStruct", "MyMethod");
//print out My statement."
所以我想,首先我需要像StructByName()
之类的东西,然后将其用于MethodByName()
,是吧!
答案 0 :(得分:46)
要在对象上调用方法,请先使用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{})
}
答案 1 :(得分: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")
}
真正的代码需要检查方法的输入数字或方法是否有效。 您可以参考此http://gowalker.org/reflect#Type
ret
reflect.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{} {
}
所以这没关系
color := Invoke(Circle{}, "GetColor")[0].(Color)
但是
Invoke(NotAnShape{}, "ForBar")
无法编译,因为NotAnShape
不是形状。
如果您无法确定在编译时将使用哪种第一种类型,您可以构建一个映射来存储所有可能的类型,如下所示。
map[string]reflect.Value{
"YourT1" : reflect.ValueOf(YourT1{})
"YourT2" : reflect.ValueOf(YourT2{})
"Circle" : reflect.ValueOf(Cirlce{}) // or reflect.ValueOf(&Circle{})
}
答案 2 :(得分:1)
gist 调用带有错误处理的struct方法
// Invoke - firstResult, err := Invoke(AnyStructInterface, MethodName, Params...)
func invoke(any interface{}, name string, args ...interface{}) (reflect.Value, error) {
method := reflect.ValueOf(any).MethodByName(name)
methodType := method.Type()
numIn := methodType.NumIn()
if numIn > len(args) {
return reflect.ValueOf(nil), fmt.Errorf("Method %s must have minimum %d params. Have %d", name, numIn, len(args))
}
if numIn != len(args) && !methodType.IsVariadic() {
return reflect.ValueOf(nil), fmt.Errorf("Method %s must have %d params. Have %d", name, numIn, len(args))
}
in := make([]reflect.Value, len(args))
for i := 0; i < len(args); i++ {
var inType reflect.Type
if methodType.IsVariadic() && i >= numIn-1 {
inType = methodType.In(numIn - 1).Elem()
} else {
inType = methodType.In(i)
}
argValue := reflect.ValueOf(args[i])
if !argValue.IsValid() {
return reflect.ValueOf(nil), fmt.Errorf("Method %s. Param[%d] must be %s. Have %s", name, i, inType, argValue.String())
}
argType := argValue.Type()
if argType.ConvertibleTo(inType) {
in[i] = argValue.Convert(inType)
} else {
return reflect.ValueOf(nil), fmt.Errorf("Method %s. Param[%d] must be %s. Have %s", name, i, inType, argType)
}
}
return method.Call(in)[0], nil
}
答案 3 :(得分:0)
package main
import (
"fmt"
"reflect"
)
type Log struct {
Path string
Level string
}
func (l *Log) Conversion(i interface{}) {
if data, ok := i.(*Log); ok {
if data != nil {
if len(data.Path) > 0 {
l.Path = data.Path
}
if len(data.Level) > 0 {
l.Level = data.Level
}
}
}
}
type Storage struct {
Type string
ServerList []string
}
func (s *Storage) Conversion(i interface{}) {
if data, ok := i.(*Storage); ok {
if data != nil {
if len(data.Type) > 0 {
s.Type = data.Type
}
}
}
}
type Server struct {
LogConfig *Log
StorageConfig *Storage
}
func main() {
def := Server{
LogConfig: &Log{
Path: "/your/old/log/path/",
Level: "info",
},
StorageConfig: &Storage{
Type: "zookeeper",
ServerList: []string{"127.0.0.1:2181"},
},
}
fmt.Println(def)
cur := Server{
LogConfig: &Log{
Path: "/your/new/log/path/",
Level: "debug",
},
StorageConfig: &Storage{
Type: "etcd",
ServerList: []string{"127.0.0.1:2379"},
},
}
fmt.Println(cur)
defV := reflect.ValueOf(def)
curV := reflect.ValueOf(cur)
for k := 0; k < defV.NumField(); k++ {
in := make([]reflect.Value, 1)
in[0] = reflect.ValueOf(curV.Field(k).Interface())
defV.Field(k).MethodByName("Conversion").Call(in)
}
fmt.Println(def.LogConfig)
fmt.Println(def.StorageConfig)
}