Home > other >  Golang inheritance - Cannot use (type func(d Dog)) as the type func(animal Animal)
Golang inheritance - Cannot use (type func(d Dog)) as the type func(animal Animal)

Time:10-22

I was tring to write a method callGetName which can take both getCatName and getDogName method as its parameter while my IDE tells me:

Cannot use 'getDogName' (type func(d Dog)) as the type func(animal Animal)

package main

type Animal struct {
    Name string
}
type Cat struct {
    Animal
}
type Dog struct {
    Animal
}

func getCatById(c Cat) {}
func validateDogNames(d Dog) {}

func invokeFunc(f func(animal Animal)) {}

func main() {
    invokeFunc(getCatById)
    invokeFunc(validateDogNames)
}

I tried to analyze the reason, maybe it's because golang supports multiple inheritance?

Please let me know if I was doing something stupid or is there any better way to achieve this?

========

A little more about why I'm trying this: in go-kit framework, I have to write makeEndpoint functions for every single service method defined. And I used reflect to adopt a generic makeEndpoints like below:

func NewProductEndpoints() ProductEndpoints {
    ps := service.NewProductService()
    return ProductEndpoints{
        GetProductById: makeEndpoint(ps, util.GetFunctionName(ps.GetProductById)),
        CreateProduct: makeEndpoint(ps, util.GetFunctionName(ps.CreateProduct)),
    }
}

func makeEndpoint(s service.ProductService, funcName string) kitEndpoint.Endpoint {
    return func(ctx context.Context, request interface{}) (response interface{}, err error) {
        req := request.(domain.ProductDTO)
        currFunc := reflect.ValueOf(s).MethodByName(funcName)
        args := []reflect.Value{reflect.ValueOf(req)}
        res := currFunc.Call(args)[0]
        return res, nil
    }
}

wondering if there's a better way to achieve. Thanks in advance.

CodePudding user response:

So you're thinking in a fairly OOP fashion, Go does not have inheritance (to clarify it has struct embedding which is what you are doing in your first example). We tend to favour composition to solve problems.

One way you could look at solving your problem is like the below.

package main

import (
    "fmt"
)

type Namer interface {
    Name() string
}

type Cat struct {
    name string
}

func (c Cat) Name() string {
    return c.name
}

type Dog struct {
    name string
}

func (d Dog) Name() string {
    return d.name
}

func PetName(n Namer) {
    fmt.Println(n.Name())
}

func main() {
    PetName(Dog{name: "Fido"})
    PetName(Cat{name: "Mittens"})
}

Names can be improved, but it should act as a basic example of an approach that could be taken.

Edit: Example based on comment left below

package main

import (
    "fmt"
)

type Invoker interface {
    Invoke()
}

type Dog struct{}

func (Dog) Bark() {
    fmt.Println("Woof")
}
func (d Dog) Invoke() {
    d.Bark()
}

type Cat struct{}

func (Cat) Meow() {
    fmt.Println("Meow")
}
func (c Cat) Invoke() {
    c.Meow()
}

func CallFunc(i Invoker) {
    i.Invoke()
}

func main() {
    CallFunc(Cat{})
    CallFunc(Dog{})
}
  • Related