Go中的动态函数调用

Eri*_*ric 6 go first-class-functions

我正在尝试动态调用返回不同类型的函数struct.

例如,让我们采用以下代码.

struct A {
   Name string
   Value  int
}

struct B {
   Name1 string
   Name2 string
   Value   float
}

func doA() (A) {
   // some code returning A
}

func doB() (B) {
   // some code returning B
}
Run Code Online (Sandbox Code Playgroud)

我想将函数doAdoB作为参数传递给将执行函数和JSON编码结果的泛型函数.如下:

func Generic(w io.Writer, fn func() (interface {}) {
    result := fn()
    json.NewEncoder(w).Encode(result)
}
Run Code Online (Sandbox Code Playgroud)

但当我这样做时:

Generic(w, doA)
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

cannot use doA (type func() (A)) as type func() (interface {})
Run Code Online (Sandbox Code Playgroud)

有没有办法实现这种动态调用?

Mic*_*zlo 8

首先,让我注意这func() (interface{})意味着同样的事情func() interface{},所以我将使用更短的形式.

传递类型的功能 func() interface{}

func() interface{}只要传递给它的函数具有类型func() interface{},就可以编写一个带参数的泛型函数,如下所示:

type A struct {
    Name  string
    Value int
}

type B struct {
    Name1 string
    Name2 string
    Value float64
}

func doA() interface{} {
    return &A{"Cats", 10}
}

func doB() interface{} {
    return &B{"Cats", "Dogs", 10.0}
}

func Generic(w io.Writer, fn func() interface{}) {
    result := fn()
    json.NewEncoder(w).Encode(result)
}
Run Code Online (Sandbox Code Playgroud)

您可以在实时游乐场中试用此代码:

http://play.golang.org/p/JJeww9zNhE

将函数作为类型的参数传递 interface{}

如果要编写函数doAdoB返回具体类型的值,则可以将所选函数作为类型的参数传递interface{}.然后你可以使用reflect做出func() interface{}在运行时:

func Generic(w io.Writer, f interface{}) {
    fnValue := reflect.ValueOf(f)        // Make a concrete value.
    arguments := []reflect.Value{}       // Make an empty argument list.
    fnResults := fnValue.Call(arguments) // Assume we have a function. Call it.
    result := fnResults[0].Interface()   // Get the first result as interface{}.
    json.NewEncoder(w).Encode(result)    // JSON-encode the result.
}
Run Code Online (Sandbox Code Playgroud)

更简洁:

func Generic(w io.Writer, fn interface{}) {
    result := reflect.ValueOf(fn).Call([]reflect.Value{})[0].Interface()
    json.NewEncoder(w).Encode(result)
}
Run Code Online (Sandbox Code Playgroud)

完整计划:

包主

import (
    "encoding/json"
    "io"
    "os"
    "reflect"
)

type A struct {
    Name  string
    Value int
}

type B struct {
    Name1 string
    Name2 string
    Value float64
}

func doA() *A {
    return &A{"Cats", 10}
}

func doB() *B {
    return &B{"Cats", "Dogs", 10.0}
}

func Generic(w io.Writer, fn interface{}) {
    result := reflect.ValueOf(fn).Call([]reflect.Value{})[0].Interface()
    json.NewEncoder(w).Encode(result)
}

func main() {
    Generic(os.Stdout, doA)
    Generic(os.Stdout, doB)
}
Run Code Online (Sandbox Code Playgroud)

现场操场:

http://play.golang.org/p/9M5Gr2HDRN