Go中的动态函数调用
Dynamic function call in 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 {})
有没有办法实现这种动态调用?
您的 return 签名对于这些函数是不同的:
fn func() (interface {})
对比 func doA() (A)
和 func doB() (B)
您收到编译器错误,因为您将具有不同签名的函数传递给 Generic
函数。要解决此问题,您可以将函数更改为 return interface{}
.
这是一个如何做到这一点的例子,我使用匿名结构并打印出 return 值而不是序列化它们,但这同样适用于你的例子:
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
首先,让我说明 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)
}
您可以在现场 playground 中试用此代码:
http://play.golang.org/p/JJeww9zNhE
将函数作为 interface{}
类型的参数传递
如果您想编写函数 doA
和 doB
return 具体类型值,您可以将所选函数作为类型 interface{}
的参数传递。然后你可以使用 reflect
package 在 运行 时创建一个 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)
}
现场游乐场:
我正在尝试动态调用返回不同类型 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 {})
有没有办法实现这种动态调用?
您的 return 签名对于这些函数是不同的:
fn func() (interface {})
对比 func doA() (A)
和 func doB() (B)
您收到编译器错误,因为您将具有不同签名的函数传递给 Generic
函数。要解决此问题,您可以将函数更改为 return interface{}
.
这是一个如何做到这一点的例子,我使用匿名结构并打印出 return 值而不是序列化它们,但这同样适用于你的例子:
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
首先,让我说明 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)
}
您可以在现场 playground 中试用此代码:
http://play.golang.org/p/JJeww9zNhE
将函数作为 interface{}
类型的参数传递
如果您想编写函数 doA
和 doB
return 具体类型值,您可以将所选函数作为类型 interface{}
的参数传递。然后你可以使用 reflect
package 在 运行 时创建一个 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)
}
现场游乐场: