英文:
Examining the signature of function assigned to an interface{} variable using reflection
问题
我正在尝试构建一个类似于以下代码的通用柯里化函数:
package curry
import (
"fmt"
"reflect"
)
// 函数类型
type fn interface{}
// 函数参数类型
type pr interface{}
// 返回柯里化后的函数
func It(f fn, p ...pr) (fn, error) {
// 检查函数 f 的具体类型
if reflect.ValueOf(f).Kind() == reflect.Func {
// 获取输入和输出参数类型的切片
} else {
return nil, fmt.Errorf("%s", "第一个参数必须是一个函数")
}
// _, _ = f, p
return nil, nil
}
是否可以提取函数 f
的输入和输出参数类型的切片 []reflect.Type
?
英文:
I'm trying the build a [tag:generic] [tag:currying] function that's look like:
package curry
import (
"fmt"
"reflect"
)
// Function
type fn interface{}
// Function parameter
type pr interface{}
// It return the curried function
func It(f fn, p ...pr) (fn, error) {
// examine the concret type of the function f
if reflect.ValueOf(f).Kind() == reflect.Func {
// Get the slice of input and output parameters type
} else {
return nil, fmt.Errorf("%s", "takes a function as a first parameter")
}
// _, _ = f, p
return nil, nil
}
Is it possible to extract the slice of input and output parameters types as []reflect.Type
of the function f
?
答案1
得分: 3
你可以使用reflect.Type.In(int)
和reflect.Type.Out(int)
,它们有对应的方法NumIn() int
和NumOut() int
,可以获取输入/输出的数量。
然而,需要注意以下几点:
- 要正确提取任意签名的函数,你需要无限多个情况。你需要逐个切换每个In和Out,以正确获取要提取的类型。
- 无论如何都不能动态创建函数。没有与SliceOf、MapOf等方法相对应的FuncOf方法。你必须手动编写柯里化版本。
- 使用反射来模拟泛型通常被认为是一个不好的主意。
如果你非常需要做类似的事情,我强烈建议创建一个接口,并让每个实现自己进行柯里化,而不是试图在所有情况下进行“通用”处理,这在Go 1.2.1中是行不通的。
英文:
You can use reflect.Type.In(int)
and reflect.Type.Out(int)
, there are corresponding methods called NumIn() int
and NumOut() int
that give you the number of inputs/outputs.
However, keep in mind a few caveats:
- To correctly extract the function for an arbitrary signature, you'll need an infinite number of cases. You'll have to switch over every single In and Out in turn to correctly get the type to extract.
- You can't dynamically create a function anyway. There's no FuncOf method to go with SliceOf, MapOf, etc. You'll have to hand code the curried versions anyway.
- Using reflection to emulate generics is generally considered a Bad Idea™.
If you absolutely have to do something like this, I'd heavily recommend making an interface and having each implementation do the currying itself, rather than trying to hack it "generically" for all cases, which will never work as of Go 1.2.1.
答案2
得分: 2
Go 1.5将添加一个可以帮助的函数。
(review 1996,commit e1c1fa2 by Dave (okdave
))
// FuncOf返回具有给定参数和结果类型的函数类型。
// 例如,如果k表示int,e表示string,
// FuncOf([]Type{k}, []Type{e}, false)表示func(int) string。
//
// 可变参数控制函数是否是可变参数。如果in[len(in)-1]不表示切片并且variadic为true,则FuncOf会引发panic。
func FuncOf(in, out []Type, variadic bool) Type
测试用例包括以下有趣的代码:
v := MakeFunc(FuncOf([]Type{TypeOf(K(""))}, []Type{TypeOf(V(0))}, false), fn)
outs := v.Call([]Value{ValueOf(K("gopher"))})
英文:
Go 1.5 will add a function that could help here.
(review 1996, commit e1c1fa2 by Dave (okdave
))
// FuncOf returns the function type with the given argument and result types.
// For example if k represents int and e represents string,
// FuncOf([]Type{k}, []Type{e}, false) represents func(int) string.
//
// The variadic argument controls whether the function is variadic. FuncOf
// panics if the in[len(in)-1] does not represent a slice and variadic is
// true.
func FuncOf(in, out []Type, variadic bool) Type
The test cases include this intriguing code:
v := MakeFunc(FuncOf([]Type{TypeOf(K(""))}, []Type{TypeOf(V(0))}, false), fn)
outs := v.Call([]Value{ValueOf(K("gopher"))})
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论