有func someFunc(v interface{}, fn interface{})
其中v
是指向struct的指针(比如*A
),fn是方法表达式(比如(*A).method()
)。如何使用fn
作为参数调用v
(使用reflect
)?
答案 0 :(得分:0)
可以使用reflect.Value.Call()
,但这非常麻烦,特别是如果您需要对返回值执行某些操作。但这是一个基本的例子:
package main
import (
"fmt"
"reflect"
)
type Foo struct {
Bar string
}
func concrete(foo *Foo) {
fmt.Printf("Foo: %#v\n", foo)
}
func someFunc(v interface{}, fn interface{}) {
f := reflect.ValueOf(fn)
arg := reflect.ValueOf(v)
f.Call([]reflect.Value{arg})
}
func main() {
foo := Foo{"Bar"}
someFunc(&foo, concrete)
}
// Output: Foo: &main.Foo{Bar:"Bar"}
https://play.golang.org/p/ED6QdvENxti
如果你想按名称调用struct的方法,我们需要稍微修改一下:
type Foo struct {
Bar string
}
func (f *Foo) Concrete() {
fmt.Printf("Foo: %#v\n", f)
}
func callByName(v interface{}, fn string) {
arg := reflect.ValueOf(v)
f := arg.MethodByName(fn)
f.Call([]reflect.Value{})
}
func main() {
foo := Foo{"Bar"}
callByName(&foo, "Concrete")
}
请注意,在这种情况下,方法值已绑定到struct实例,因此我们不需要将任何内容作为参数传递。
答案 1 :(得分:-3)
因此,对于使用reflect来调用方法而不知道名称并且是同一类型的方法(op(orignally)解决)的挑战,我提出了一种非常非常丑陋且不安全的方法。
package main
import (
"fmt"
"reflect"
"runtime"
"strings"
)
func getFName(v reflect.Value) string {
return runtime.FuncForPC(v.Pointer()).Name()
}
func callMethod(a,fn interface{}) {
fname:=getFName(reflect.ValueOf(fn))
parts:=strings.Split(fname,".")
name:=strings.TrimSuffix(parts[len(parts)-1],"-fm")
reflect.ValueOf(a).MethodByName(name).Call(nil)
}
func (s *a) Tst() {
fmt.Println(s)
}
type a struct { p string }
func main() {
x,y:=a{"Good"},a{"Bad"}
callMethod(&x,y.Tst)
}
游乐场:https://play.golang.org/p/QgrGhI5DC3p
我想知道更好的方法,不依赖于runtime.FuncForPc
格式化方法(不是版本安全的),但这是我所拥有的最好的方法。请告诉我任何改进它的想法。