studio - ¿Llamar a Struct y su método por su nombre en Go?
visual studio installer (3)
Para llamar a un método en un objeto, primero use reflect.ValueOf
. Luego encuentre el método por su nombre y finalmente llame al método encontrado. Por ejemplo:
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{})
}
He encontrado una función llamada MethodByName()
aquí http://golang.org/pkg/reflect/#Value.MethodByName pero no es exactamente lo que quiero! (tal vez porque no sé cómo usarlo ... no puedo encontrar ningún ejemplo con él). Lo que quiero es:
type MyStruct struct {
//some feilds here
}
func (p *MyStruct) MyMethod {
println("My statement.");
}
CallFunc("MyStruct", "MyMethod");
//print out My statement."
Así que supongo, primero necesito algo como StructByName()
y luego usarlo para MethodByName()
, ¿es eso correcto?
gist invoke struct method con manejo de errores
// 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])
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
}
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")
}
Realmente el código necesita verificar el número de entrada del método o el método en sí mismo si es válido. Puede hacer referencia a este http://gowalker.org/reflect#Type
- Marque "cualquiera" es un tipo de estructura
- Verifique que "cualquiera" tenga el método "nombre"
- Compruebe que el número de parámetros de entrada del "nombre" del método sea igual a la longitud de args
- Implementar
ret
porreflect.Value.Interface()
y ten cuidado con el tipo Ptr; o Puede usar SomeInterface{}
lugar de usar directamente la interface{}
para garantizar este tipo de "cualquier", como este
type Shape interface {
Area() float64 //some method to ensure any is an Shape type.
}
func Invoke(s Shape, name string, inputs...interface{}) []interface{} {
}
así que esto está bien
color := Invoke(Circle{}, "GetColor")[0].(Color)
pero
Invoke(NotAnShape{}, "ForBar")
no se puede compilar porque NotAnShape
no es una forma.
Si no puede estar seguro de cuál será el primer tipo que se usará en el momento de la compilación, puede crear un mapa para almacenar todo el tipo posible, como este.
map[string]reflect.Value{
"YourT1" : reflect.ValueOf(YourT1{})
"YourT2" : reflect.ValueOf(YourT2{})
"Circle" : reflect.ValueOf(Cirlce{}) // or reflect.ValueOf(&Circle{})
}