Im Bereich der Vorlagensysteme in Go spielt Reflexion eine entscheidende Rolle. Beim dynamischen Aufrufen von Methoden auf einer Schnittstelle{} mit unterschiedlichen Empfängertypen entsteht eine Herausforderung. Dies funktioniert zwar nahtlos mit bekannten Typen, schlägt jedoch fehl, wenn die Daten in eine Schnittstelle eingebettet sind{}.
Problembeschreibung
Bedenken Sie den folgenden Code:
type Test struct { Start string } func (t *Test) Finish() string { return t.Start + "finish" } func Pass(i interface{}) { _, ok := reflect.TypeOf(&i).MethodByName("Finish") if ok { fmt.Println(reflect.ValueOf(&i).MethodByName("Finish").Call([]reflect.Value{})[0]) } else { fmt.Println("Pass() fail") } } func main() { i := Test{Start: "start"} Pass(i) _, ok := reflect.TypeOf(&i).MethodByName("Finish") if ok { fmt.Println(reflect.ValueOf(&i).MethodByName("Finish").Call([]reflect.Value{})[0]) } else { fmt.Println("main() fail") } }
Beobachtungen
Das Problem
Das Problem liegt im Zugriff auf die Adresse der Daten, wenn diese in eine Schnittstelle eingebettet sind{}. Die Verwendung von &i, das normalerweise auf einen Zeiger verweist, funktioniert in diesem Szenario nicht.
Lösung
Um dieses Problem zu beheben, müssen wir alle möglichen Szenarien behandeln:
Schnittstelle{} Daten als Wert und Methodenempfänger als Wert:
Schnittstelle{} Daten als einen Wert- und Methodenempfänger als Zeiger:
Schnittstelle{} Daten als Zeiger und Methodenempfänger als Wert:
Schnittstellendaten{} als Zeiger und Methodenempfänger als Zeiger:
Implementierung
Basierend auf dieser Logik können wir eine verallgemeinerte Funktion erstellen, um Methoden dynamisch aufzurufen:
func CallMethod(i interface{}, methodName string) interface{} { // Handle all scenarios var ptr, value, finalMethod reflect.Value value = reflect.ValueOf(i) 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 and pointer method := value.MethodByName(methodName) if method.IsValid() { finalMethod = method } method = ptr.MethodByName(methodName) if method.IsValid() { finalMethod = method } // Call the method if (finalMethod.IsValid()) { return finalMethod.Call([]reflect.Value{})[0].Interface() } // Method not found return "" }
Mit dieser Funktion können wir nun Methoden unabhängig vom Empfängertyp und der Schnittstelle dynamisch aufrufen{} Wrapper:
i := Test{Start: "start"} j := Test{Start: "start2"} fmt.Println(CallMethod(i, "Finish")) // Output: startfinish fmt.Println(CallMethod(&i, "Finish")) // Output: startfinish fmt.Println(CallMethod(i, "Another")) // Output: fmt.Println(CallMethod(&i, "Another")) // Output: start2another fmt.Println(CallMethod(j, "Finish")) // Output: startfinish fmt.Println(CallMethod(&j, "Finish")) // Output: start2finish fmt.Println(CallMethod(j, "Another")) // Output: fmt.Println(CallMethod(&j, "Another")) // Output: start2another
Das obige ist der detaillierte Inhalt vonWie rufe ich Methoden auf einer Schnittstelle{} in Go dynamisch auf, unabhängig vom Empfängertyp?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!