dozc58418381 2015-09-19 21:27
浏览 142
已采纳

Go中的动态函数调用

I'm trying to dynamically call functions returning different types of struct.

For example, let's take the following code.

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
}

I would like to pass either the function doA or doB as an argument to a generic function that would execute the function and JSON-encode the result. Like the following:

func Generic(w io.Writer, fn func() (interface {}) {
    result := fn()
    json.NewEncoder(w).Encode(result)
}

But when I do:

Generic(w, doA)

I get the following error:

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

Is there a way to achieve this dynamic call?

  • 写回答

2条回答 默认 最新

  • dsd57259 2015-09-19 21:49
    关注

    First, let me remark that func() (interface{}) means the same thing as func() interface{}, so I'll use the shorter form.

    Passing a function of type func() interface{}

    You can write a generic function that takes a func() interface{} argument as long as the function that you pass to it has type func() interface{}, like this:

    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)
    }
    

    You can try out this code in a live playground:

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

    Passing a function as an argument of type interface{}

    If you want to write functions doA and doB that return concretely typed values, you can pass the chosen function as an argument of type interface{}. Then you can use the reflect package to make a func() interface{} at run-time:

    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.
    }
    

    More concisely:

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

    Complete program:

    package main

    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)
    }
    

    Live playground:

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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥170 如图所示配置eNSP
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效
  • ¥15 悬赏!微信开发者工具报错,求帮改
  • ¥20 wireshark抓不到vlan
  • ¥20 关于#stm32#的问题:需要指导自动酸碱滴定仪的原理图程序代码及仿真
  • ¥20 设计一款异域新娘的视频相亲软件需要哪些技术支持
  • ¥15 stata安慰剂检验作图但是真实值不出现在图上
  • ¥15 c程序不知道为什么得不到结果
  • ¥15 键盘指令混乱情况下的启动盘系统重装