I would like to understand why the code snippet below does not compile. What is the Go way of accepting a function as a function argument that may have any return type?
package main
func main() {
test(a) // Error: cannot use a (type func() string) as type func() interface {} in argument to test
test(b) // Error: cannot use b (type func() int) as type func() interface {} in argument to test
}
func a() string {
return "hello"
}
func b() int {
return 1
}
func test(x func() interface{}) {
// some code...
v := x()
// some more code....
}
Play: https://play.golang.org/p/CqbuEZGy12
My solution based on Volker's answer:
package main
import (
"fmt"
)
func main() {
// Wrap function a and b with an anonymous function
// that has an empty interface return type. With this
// anonymous function, the call signature of test
// can be satisfied without needing to modify the return
// type of function a and b.
test(func() interface{} {
return a()
})
test(func() interface{} {
return b()
})
}
func a() string {
return "hello"
}
func b() int {
return 1
}
func test(x func() interface{}) {
v := x()
fmt.Println(v)
}
Play: https://play.golang.org/p/waOGBZZwN7
Empty Interface to Pass Function Argument of Any Type Normally in functions, when we pass values to the function parameters, we need to specify the data type of parameters in a function definition. In the above example, we have used an empty interface i as the parameter to the displayValue() function.
The interface type that specifies zero methods is known as the empty interface: interface{} An empty interface may hold values of any type. (Every type implements at least zero methods.) Empty interfaces are used by code that handles values of unknown type.
Empty interfaces can be checked at compile-time using the type-system in the compiler. This brings no overhead at runtime at all so it is faster.
To implement an interface, you just need to implement all the methods declared in the interface. Unlike other languages like Java, you don't need to explicitly specify that a type implements an interface using something like an implements keyword.
Function with No argument and No return type. Function with No argument and Return something. A function that takes argument but returns nothing. Functions that take an argument and also return something. This is a function that takes no argument, and returns nothing.
Here is a good definition of the empty interface by Jordan Oreilli: An interface is two things: it is a set of methods, but it is also a type. The interface {} type is the interface that has no methods.
You are asking about defining an interface as a return type. If an interface is defined to be the return type of a method then instances of classes derived from that interface can be returned. The benefit of doing that is no different from returning objects of classes derived from a class.
In Go, we can also create interfaces without any methods, known as empty interfaces. For example, Here, we have created an empty interface without any methods. In Go, we can create variables of the empty interface type. For example,
You tripped over a very common misconception for Go newcomers: The empty interface interface{}
does not mean "any type". Really, it does not. Go is statically typed. The empty interface interface {}
is an actual (strongly typed type) like e.g. string
or struct{Foo int}
or interface{Explode() bool}
.
That means if something has the type interface{}
it has that type and not "any type".
Your function
func test(x func() interface{})
takes one parameter. This parameter is a (parameterless function) which returns a specific type, the type interface{}
. You can pass any function to test
which matches this signature: "No parameters and return interface{}
". None of your functions a
and b
match this signature.
As said above: interface {}
is not a magical abbreviation for "whatever",it is a distinct static type.
You have to change e.g. a to:
func a() interface{} {
return "hello"
}
Now this might look strange as you return a string
which is not of type interface{}
. This works because any type is assignable to variables of type interface{}
(as every type has at least no methods :-).
As the Go specification states:
A function type denotes the set of all functions with the same parameter and result types
In your case, your result types differ (string
vs interface{}
)
To be able to receive a function with any kind of result type, test
would have to be defined as:
func text(x interface{}) { ... }
and then you will have to use reflect package to call the function stored in x
.
Edit
Such a test
function would look like this:
func test(x interface{}) {
v := reflect.ValueOf(x)
if v.Kind() != reflect.Func {
panic("Test requires a function")
}
t := v.Type()
if t.NumIn() != 0 && t.NumOut() != 1 {
panic("Function type must have no input parameters and a single return value")
}
values := v.Call(nil)
val := values[0].Interface()
// some more code..
}
Playground: https://play.golang.org/p/trC2lOSLNE
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With