Vorlagensysteme stützen sich stark auf das Reflect-Paket in Go. Bei der Arbeit mit diesem Paket kann es zu Schwierigkeiten beim dynamischen Aufrufen von Methoden auf Schnittstellen kommen. Dieses Problem wird deutlich, wenn der Datentyp als Schnittstelle{} gespeichert wird.
Das Verständnis der Dynamik des Methodenaufrufs für Schnittstellen ist von entscheidender Bedeutung. Es sind vier Szenarien zu berücksichtigen:
Reflection kann dabei helfen, den zugrunde liegenden Datenwert einer Schnittstelle zu bestimmen. Mit diesen Informationen kann man den alternativen Datentyp generieren und zwischen Wert- und Zeigerempfängermethoden unterscheiden.
Um das Problem zu lösen, ist es notwendig, sowohl eine Wert- als auch eine Zeigerdarstellung zu erstellen der Daten:
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 }
Da beide Datentypen verfügbar sind, wird die Prüfung auf das Vorhandensein einer Methode unkompliziert:
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() }
Von Mit diesem Ansatz wird es möglich, jede Methode effektiv dynamisch aufzurufen, unabhängig davon, ob sie als Wert- oder Zeigerempfänger definiert ist.
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")) }
Ausgabe:
startfinish startfinish <nil> startanother startfinish startfinish <nil> startanother
Das obige ist der detaillierte Inhalt vonWie kann ich Methoden für Schnittstellen in Go dynamisch aufrufen und dabei sowohl Wert- als auch Zeigerempfänger verarbeiten?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!