为了账号安全,请及时绑定邮箱和手机立即绑定

Go 中的动态函数调用

Go 中的动态函数调用

Go
慕雪6442864 2021-11-08 16:17:05
我正在尝试动态调用返回不同类型的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 {})有没有办法实现这个动态调用?
查看完整描述

2 回答

?
四季花海

TA贡献1811条经验 获得超5个赞

首先,让我注意这与 的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


查看完整回答
反对 回复 2021-11-08
?
慕桂英4014372

TA贡献1871条经验 获得超13个赞

这些函数的返回签名是不同的: fn func() (interface {})vs.func doA() (A)和func doB() (B)


您收到编译器错误,因为您将具有不同签名的Generic函数传递到您的函数中。要解决此问题,您可以将函数更改为 return interface{}。


这是如何做到这一点的示例,我使用匿名结构并打印返回值而不是序列化它们,但这同样适用于您的示例:


package main


import "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


查看完整回答
反对 回复 2021-11-08
  • 2 回答
  • 0 关注
  • 340 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信