Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

interface{} to function type conversion

Tags:

go

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{} ?

like image 600
stan.sm Avatar asked Jul 07 '14 13:07

stan.sm


2 Answers

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)()
    }
}
like image 92
OneOfOne Avatar answered Dec 08 '22 22:12

OneOfOne


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.

like image 38
Elwinar Avatar answered Dec 08 '22 23:12

Elwinar