将interface{}转换为函数类型

huangapple go评论94阅读模式
英文:

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

你的问题中存在一些小的误解:

  1. 类型断言不用于类型转换。它只是检查一个变量是否是给定类型,并将该变量作为该底层类型返回。在你的情况下,这个操作会返回一个错误,这是正常的,因为func()不是类型HandlerFunc

  2. 在接受interface{}类型参数的函数中,你不需要做任何事情来传递变量。每种类型都隐式实现了空接口。

  3. func()不是HandlerType,即使HandlerType的定义是type HandlerType func()。这个定义与此无关。

你想做的事情是不可能的。我对反射不是很熟悉,但我认为反射也无法解决你的问题。

也就是说,你的注册方法应该定义一个接口,所有注册的对象都应该实现这个接口,并将该接口作为参数类型。可以参考database/sql包中的Register方法作为示例。

英文:

There is a number of small misconceptions in your question:

  1. 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 type HandlerFunc.

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

  3. A func() isn't a HandlerType, even if HandlerType is defined by type 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

huangapple
  • 本文由 发表于 2014年7月7日 21:11:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/24611416.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定