英文:
interface{} to function type conversion
问题
我是一名Go的新手,今天几乎整天都在解决这个问题。
考虑到我有以下代码:
type HandlerType func()
var object interface{}
var typedObject HandlerType
我可以像这样将一个函数赋值给typedObject变量:
typedHandler = func() {
fmt.Println("in a handler!\n")
}
但是我需要做的是将该处理程序函数作为interface{}变量传递,然后以某种方式将其转换为HandlerType,以便稍后调用它。
我尝试了以下代码,但是它会抛出一个错误:
typedHandler = object.(HandlerType)
结果是:
interface conversion: interface is func(), not main.HandlerType
基本上,我需要注册具有不同签名的函数,而无需在注册之前进行额外的类型转换。所以,我想要这样注册处理程序:
registerHandler(func() string { ... })
registerHandler(func() { ... })
...并且我不想在稍后调用处理程序时使用反射。
这种可能吗?
编辑:我创建了一个playground:http://play.golang.org/p/UlwqkHjt_P
所以,我理解的是没有办法将某个任意函数传递为interface{},然后以某种方式将其转换为HandlerType或其他预定义的函数类型,以便在不使用反射的情况下调用它?
编辑2:我想出了这个解决方案:http://play.golang.org/p/4gUxsgmiPf
在运行时,这段代码不应该有任何性能损失。但是,有没有人能想出另一种在不使用**interface{}**的情况下实现这个功能的方法?
英文:
I'm a Go newcomer and I've been battling with this problem almost all day today.
Considering I have these:
type HandlerType func()
var object interface{}
var typedObject HandlerType
I can assign a function to the typedObject variable like this:
typedHandler = func() {
fmt.Println("in a handler!\n")
}
But what I need to do is to pass that handler function as an interface{} variable and then convert it somehow to HandlerType which I could call later
I've tried this but it throws an error:
typedHandler = object.(HandlerType)
results in:
> interface conversion: interface is func(), not main.HandlerType
Basically I need to register functions with different signatures without additional type conversion before registering. So instead of doing this:
registerHandler(HandlerTypeString(func() string { ... }))
registerHandler(HandlerTypeVoid(func() { ... }))
I want to register handlers like this:
registerHandler(func() string { ... })
registerHandler(func() { ... })
.. and I don't want to involve reflection at the time of a handler call later
Is it possible?
Edit: I've created a playground: http://play.golang.org/p/UlwqkHjt_P
So as I understand there is no way to pass some arbitrary function as interface{} and then somehow convert it to HandlerType or some other predefined function type so I would be able to call it without using reflection?
Edit2: I've came up with this solution: http://play.golang.org/p/4gUxsgmiPf
There shouldn't be any performance penalties during runtime with this code. But can somebody think out another way of implementing this functionality without interface{} ?
答案1
得分: 17
你无法这样做,因为它们是不同的类型,你只能使用object.(func())
、object.(func() string)
等方式。
func main() {
type HandlerType func()
var object interface{} = func() {
fmt.Println("eureka!")
}
if f, ok := object.(func()); ok {
HandlerType(f)()
}
}
英文:
You can't, it's a different type, you could just use object.(func())
, object.(func() string)
, etc.
func main() {
type HandlerType func()
var object interface{} = func() {
fmt.Println("eureka!")
}
if f, ok := object.(func()); ok {
HandlerType(f)()
}
}
答案2
得分: 8
你的问题中存在一些小的误解:
-
类型断言不用于类型转换。它只是检查一个变量是否是给定类型,并将该变量作为该底层类型返回。在你的情况下,这个操作会返回一个错误,这是正常的,因为
func()
不是类型HandlerFunc
。 -
在接受
interface{}
类型参数的函数中,你不需要做任何事情来传递变量。每种类型都隐式实现了空接口。 -
func()
不是HandlerType
,即使HandlerType
的定义是type HandlerType func()
。这个定义与此无关。
你想做的事情是不可能的。我对反射不是很熟悉,但我认为反射也无法解决你的问题。
也就是说,你的注册方法应该定义一个接口,所有注册的对象都应该实现这个接口,并将该接口作为参数类型。可以参考database/sql
包中的Register
方法作为示例。
英文:
There is a number of small misconceptions in your question:
-
Type assertion isn't used to cast types. All it do is checking that a variable is of the given type and returning the variable as this underlying type. This operation return a error in your case, which is normal given that
func()
isn't the typeHandlerFunc
. -
You don't need to do anything to pass a variable as parameter in a function accepting
interface{}
. Every type implicitly implement the empty interface. -
A
func()
isn't aHandlerType
, even ifHandlerType
is defined bytype HandlerType func()
. The definition has nothing to do with that.
What you want to do isn't possible. I'm not an expert with reflection, but I don't think that reflection could solve your problem either.
That said, your registering method should define a interface that all registered objects should implement, and use this interface as parameter type. Look at the database/sql
package Register
method for an example.
答案3
得分: 0
你现在可以使用reflect.MakeFunc来实现这个。那里有一个示例,展示了如何做到这一点。
英文:
You can do this now with the reflect.MakeFunc There is an example there on how to do it
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论