Mustafa
Mustafa

Reputation: 10413

Golang Passing Function Arguments with Arbitrary Interfaces

The following code works nicely:

package main

import (
    "fmt"
)

func WrapperFunc(fn func(int,int) int) int{
    return fn(3,4)
}

func add(a,b int) int{
    return a + b
}

func main(){
    fmt.Println(WrapperFunc(add))
}

I want to pass additional parameters that implements a specific interface. For instance, I modify the code as follows:

import (
    "fmt"
)

type RequestBody interface {
    GetDescription() string
}

type LoginRequest struct {
    Username string
    Password string
}

func (lr LoginRequest) GetDescription() string{
    return "cool function"
}

func WrapperFunc(fn func(int, int, RequestBody) int) int {
    lr := LoginRequest{}
    return fn(3, 4, lr)
}

func add(a, b int, lr LoginRequest) int {
    fmt.Println(lr.GetDescription())
    return a + b
}

func main() {
    fmt.Println(WrapperFunc(add))
}

It fails with the error below:

cannot use add (type func(int, int, LoginRequest) int) as type func(int, int, RequestBody) int in argument to WrapperFunc

However, when I do not implement the GetDescription as below:

package main

import (
    "fmt"
)

type RequestBody interface {
    GetDescription() string
}

type LoginRequest struct {
    Username string
    Password string
}

func WrapperFunc(fn func(int, int, RequestBody) int) int {
    lr := LoginRequest{}
    return fn(3, 4, lr)
}

func add(a, b int, lr LoginRequest) int {
    return a + b
}

func main() {
    fmt.Println(WrapperFunc(add))
}

It fails with second error, as interface is not implemented (as expected).

cannot use lr (type LoginRequest) as type RequestBody in argument to fn:
    LoginRequest does not implement RequestBody (missing GetDescription method)
 cannot use add (type func(int, int, LoginRequest) int) as type func(int, int, RequestBody) int in argument to WrapperFunc

So, it understands that, in WrapperFunc body, I can only call fn with int, int and an RequestBody interface that implements the GetDescription, yet I still cannot pass it in the function phase. How can I accomplish this? I want to wrap functions that can have parameters that their type can change.

Upvotes: 3

Views: 2422

Answers (1)

icza
icza

Reputation: 417502

The problem is that WrapperFunc() expects a value of function type:

func(int, int, RequestBody) int

And you try to pass add to it which has a function type:

func(int, int, LoginRequest) int

2 function types are equal if both have the same parameter and result types. This does not hold in the above mentioned 2 function types: RequestBody and LoginRequest are different types, and so function types having these as (or among) parameters are different types.

You may only pass add to WrapperFunc() if you change its parameters to match the required type:

func add(a, b int, lr RequestBody) int {
    fmt.Println(lr.GetDescription())
    return a + b
}

Now add() has the same function type as fn in the parameters of WrapperFunc(), so your code will compile and run.

Output (try it on the Go Playground)

cool function
7

Notes:

Now lr parameter in add() is of type RequestBody and not LoginRequest. You may use it like a RequestBody, which is you may call its GetDescription() method. In WrapperFunc() you don't have to change anything, as LoginRequest implements RequestBody, so it is allowed to call fn() with a value of LoginRequest, and an interface value of type RequestBody will automatically, implicitly be created and passed to fn (which is add() in your case).

Note that in add() since parameter is now a RequestBody, you can't refer to fields of LoginRequest. You may if the value implementing the interface is indeed a value of type LoginRequest, in which case you may use type assertion to obtain the wrapped LoginRequest value should you need it.

Upvotes: 2

Related Questions