J'ai trouvé un appel de fonction MethodByName()
ici http://golang.org/pkg/reflect/#Value.MethodByName mais ce n'est pas exactement ce que je veux! (peut-être parce que je ne sais pas comment l'utiliser ... Je ne trouve aucun exemple avec cela). Ce que je veux c'est:
type MyStruct struct {
//some feilds here
}
func (p *MyStruct) MyMethod {
println("My statement.");
}
CallFunc("MyStruct", "MyMethod");
//print out My statement."
Donc, je suppose que, d’abord, j’ai besoin de quelque chose comme StructByName()
et que je l’utilise ensuite pour MethodByName()
, est-ce exact?
Pour appeler une méthode sur un objet, utilisez d'abord reflect.ValueOf
. Recherchez ensuite la méthode par son nom, puis appelez finalement la méthode trouvée. Par exemple:
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{})
}
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")
}
Vraiment le code doit vérifier le numéro d’entrée de la méthode ou s’auto-vérifier valablement. Vous pouvez référencer ceci http://gowalker.org/reflect#Type
ret
par reflect.Value.Interface()
et faites attention au type Ptr; ou Vous pouvez utiliser SomeInterface{}
au lieu d’utiliser directement interface{}
pour vous assurer que ce type "n’importe", comme ceci
type Shape interface {
Area() float64 //some method to ensure any is an Shape type.
}
func Invoke(s Shape, name string, inputs...interface{}) []interface{} {
}
alors c'est OK
color := Invoke(Circle{}, "GetColor")[0].(Color)
mais
Invoke(NotAnShape{}, "ForBar")
ne peut pas être compilé car NotAnShape
n'est pas une forme.
Si vous ne savez pas quel premier type sera utilisé lors de la compilation, vous pouvez créer une carte pour stocker tous les types possibles, comme ceci.
map[string]reflect.Value{
"YourT1" : reflect.ValueOf(YourT1{})
"YourT2" : reflect.ValueOf(YourT2{})
"Circle" : reflect.ValueOf(Cirlce{}) // or reflect.ValueOf(&Circle{})
}
Gist Invoque la méthode struct avec traitement des erreurs
// 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
}
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)
}