猿问

Go 中的动态函数调用

我正在尝试动态调用返回不同类型的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

}

我想将函数doA或doB作为参数传递给一个通用函数,该函数将执行该函数并对结果进行 JSON 编码。像下面这样:


func Generic(w io.Writer, fn func() (interface {}) {

    result := fn()

    json.NewEncoder(w).Encode(result)

}

但是当我这样做时:


Generic(w, doA)

我收到以下错误:


cannot use doA (type func() (A)) as type func() (interface {})

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


慕雪6442864
浏览 341回答 2
2回答

四季花海

首先,让我注意这与 的func() (interface{})含义相同func() interface{},因此我将使用较短的形式。传递类型的函数 func() interface{}func() interface{}只要传递给它的函数具有 type 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)}您可以在实时操场上试用此代码:http://play.golang.org/p/JJeww9zNhE将函数作为类型参数传递 interface{}如果要编写函数doA并doB返回具体类型的值,则可以将所选函数作为 type 参数传递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.}更简洁:func Generic(w io.Writer, fn interface{}) {    result := reflect.ValueOf(fn).Call([]reflect.Value{})[0].Interface()    json.NewEncoder(w).Encode(result)}完整程序:包主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)}现场游乐场:http://play.golang.org/p/9M5Gr2HDRN

慕桂英4014372

这些函数的返回签名是不同的: fn func() (interface {})vs.func doA() (A)和func doB() (B)您收到编译器错误,因为您将具有不同签名的Generic函数传递到您的函数中。要解决此问题,您可以将函数更改为 return interface{}。这是如何做到这一点的示例,我使用匿名结构并打印返回值而不是序列化它们,但这同样适用于您的示例:package mainimport "fmt"func doA() interface{} {    return struct {        Name  string        Value int    }{        "something",        5,    }}func doB() interface{} {    return struct {        Name1 string        Name2 string        Value float64    }{        "something",        "or other",        5.3,    }}func main() {    fmt.Println("Hello, playground", doA(), doB())}在 Go Playground 中对此进行实验:http : //play.golang.org/p/orrJw2XMW8
随时随地看视频慕课网APP

相关分类

Go
我要回答