Les systèmes de création de modèles s'appuient fortement sur le package Reflect de Go. Lorsque vous travaillez avec ce package, vous pourriez rencontrer des difficultés pour appeler dynamiquement des méthodes sur les interfaces. Ce problème devient apparent lorsque le type de données est stocké en tant qu'interface{}.
Comprendre la dynamique de l'invocation de méthode pour les interfaces est crucial. Il y a quatre scénarios à considérer :
La réflexion peut aider à déterminer la valeur des données sous-jacentes d'une interface. Avec ces informations, on peut générer le type de données alternatif et différencier les méthodes de réception de valeur et de pointeur.
Pour résoudre le problème, il est nécessaire de créer à la fois une valeur et une représentation de pointeur. des données :
value := reflect.ValueOf(data) if value.Type().Kind() == reflect.Ptr { ptr = value value = ptr.Elem() // acquire value referenced by pointer } else { ptr = reflect.New(reflect.TypeOf(i)) // create new pointer temp := ptr.Elem() // create variable to value of pointer temp.Set(value) // set value of variable to our passed in value }
Avec les deux types de données disponibles, vérifier la présence d'une méthode devient simple :
var finalMethod reflect.Value method := value.MethodByName(methodName) if method.IsValid() { finalMethod = method } // check for method on pointer method = ptr.MethodByName(methodName) if method.IsValid() { finalMethod = method } if (finalMethod.IsValid()) { return finalMethod.Call([]reflect.Value{})[0].String() }
Par en adoptant cette approche, il devient possible d'invoquer efficacement n'importe quelle méthode de manière dynamique, qu'elle soit définie comme un récepteur de valeur ou de pointeur.
package main import ( "fmt" "reflect" ) type Test struct { Start string } // value receiver func (t Test) Finish() string { return t.Start + "finish" } // pointer receiver func (t *Test) Another() string { return t.Start + "another" } func CallMethod(i interface{}, methodName string) interface{} { var ptr reflect.Value var value reflect.Value var finalMethod reflect.Value value = reflect.ValueOf(i) // if we start with a pointer, we need to get value pointed to // if we start with a value, we need to get a pointer to that value if value.Type().Kind() == reflect.Ptr { ptr = value value = ptr.Elem() } else { ptr = reflect.New(reflect.TypeOf(i)) temp := ptr.Elem() temp.Set(value) } // check for method on value method := value.MethodByName(methodName) if method.IsValid() { finalMethod = method } // check for method on pointer method = ptr.MethodByName(methodName) if method.IsValid() { finalMethod = method } if (finalMethod.IsValid()) { return finalMethod.Call([]reflect.Value{})[0].Interface() } // return or panic, method not found of either type return "" } func main() { i := Test{Start: "start"} j := Test{Start: "start2"} fmt.Println(CallMethod(i, "Finish")) fmt.Println(CallMethod(&i, "Finish")) fmt.Println(CallMethod(i, "Another")) fmt.Println(CallMethod(&i, "Another")) fmt.Println(CallMethod(j, "Finish")) fmt.Println(CallMethod(&j, "Finish")) fmt.Println(CallMethod(j, "Another")) fmt.Println(CallMethod(&j, "Another")) }
Sortie :
startfinish startfinish <nil> startanother startfinish startfinish <nil> startanother
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!