Rufen Sie unabhängig vom Empfängertyp die Methode auf der Schnittstelle {} dynamisch auf

Ich arbeite an einem Templating-System, das in Go geschrieben wurde, was bedeutet, dass es eine liberale Verwendung des erfordertreflect Paket. In diesem speziellen Fall muss ich in der Lage sein, eine Methode auf einem dynamisch aufzurufeninterface{}. Die Kuriosität ist, dass meine Reflektionslogik gut funktioniert, solange meine Daten von einem bekannten Typ sind, aber nicht, wenn die Daten vom Typ sindinterface{}.

Im folgenden Beispiel können Sie sehen, dass die Logik inmain() undPass() ist identisch. Der einzige Unterschied besteht darin, ob es sich bei den Daten um einen bekannten Typ oder einen bekannten Typ innerhalb von handeltinterface{}

Geh spielen:http://play.golang.org/p/FTP3wgc0sZ

package main

import (
    "fmt"
    "reflect"
)

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")
    }
}

Wenn wir diesen Code ausführen, erhalten wir das folgende Ergebnis

Pass() fail
startfinish

Das bedeutet, dass meine Methode zum dynamischen Aufrufen einer Methode einwandfrei funktioniert, außer in einem Szenario, in dem sich mein Objekt derzeit in einer befindetinterface{}.

Wenn ich stattdessen keinen Zeigerempfänger benutze und weitergebei dann funktioniert es wie erwartet.

Geh spielen:http://play.golang.org/p/myM0UXVYzX

Dies lässt mich glauben, dass mein Problem darin besteht, dass ich nicht auf die Adresse von i zugreifen kann (&i) wenn es eininterface{}. Ich habe das Reflect-Paket durchsucht und Dinge wie getestetreflect.Value.Addr() undreflect.PtrTo() aber ich konnte auch nicht so arbeiten, wie ich es brauchte. Meine Vermutung ist, dass es etwas damit zu tun hat, dass eininterface{} ist per definitionem ein Referenzobjekt.

Antworten auf die Frage(3)

Ihre Antwort auf die Frage