Reputation: 1884
I am attempting to write a function that accepts either some type of content of arbitrary type or a function that can generate and return an arbitrary type. To do this, I have to be able to generally test if an argument is a function without testing for whether it is a function of return type X. How do I do this? Might look something like the following:
func Blah(arbitrary interface{}) {
var value interface{}
if function, ok := arbitrary.(func interface{}); ok {
value = function()
} else {
value = arbitrary
}
...
}
This fails as is. Maybe a type assertion isn't the thing to use here. Or maybe I just don't know the syntax. Would appreciate any suggestions. Only thing I know to do at present is to divide this up into two functions, one that accepts data to be stored as is, and another that expects to get a function, but that seems overkill when in both cases the goal is simply to get a value and pass it on to the rest of the function.
Any ideas on this?
Upvotes: 1
Views: 2729
Reputation: 6425
Type assertions work on specific types. If you know that the type of the function always has type func() interface{}
, then you can use:
if f, ok := arbitrary.(func() interface{}) {
value = f()
} else {
value = arbitrary
}
Note that the type func() interface{}
is a function with return type interface{}
, not a function with an arbitrary return type.
It's easy to wrap an arbitrary function to a func() interface{}
:
func hello() string { return "hello" }
wrapped := func() interface{} { return hello() }
If you cannot arrange for the function to have return type interface{}
, then you need to use reflection to test and call the function:
func isFunction(v interface{}) (func() interface{}, bool) {
rv := reflect.ValueOf(v)
if rv.Kind() == reflect.Func {
return func() interface{} {
result := rv.Call(nil)
if len(result) > 0 {
return result[0].Interface()
}
return nil
}, true
}
return nil, false
}
---
if f, ok := isFunction(arbitrary); ok {
value = f
} else {
value = arbitrary
}
Upvotes: 5