17
votes

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

3
Show full code. typedHandler = object.(HandlerType) will work if object (of type interface {}) really contains an object of HandlerType. Show code which is playable on the playground.Volker
One more: If you are a Go newcommer you should avoid interface{}. Finde some other way, writer proper Go code. A newcomer's which for interface{} magic smells like code transliteration from some other language.Volker
I've added a playground where I think I've made clear of what do I want to accomplish :)stan.sm

3 Answers

13
votes

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)()
    }
}
8
votes

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.

0
votes

You can do this now with the reflect.MakeFunc There is an example there on how to do it