使用指针结构作为接收器调用方法表达式

时间:2018-01-30 10:24:00

标签: go reflection

func someFunc(v interface{}, fn interface{})其中v是指向struct的指针(比如*A),fn是方法表达式(比如(*A).method())。如何使用fn作为参数调用v(使用reflect)?

2 个答案:

答案 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格式化方法(不是版本安全的),但这是我所拥有的最好的方法。请告诉我任何改进它的想法。