Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accept function in argument with empty interface return type

Tags:

go

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

like image 966
Sam Herrmann Avatar asked Sep 02 '15 06:09

Sam Herrmann


People also ask

How do you pass an empty interface?

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.

What is empty interface?

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.

Why use empty interface?

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.

How do you implement an interface in Golang?

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.

What is a function with no argument and return?

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.

What is an empty interface?

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.

Can an interface be the return type of a method?

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.

What is an empty interface in Golang?

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,


2 Answers

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 :-).

like image 184
Volker Avatar answered Oct 30 '22 14:10

Volker


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

like image 32
ANisus Avatar answered Oct 30 '22 13:10

ANisus