Alex
Alex

Reputation: 36101

Generic function using embeddable structs

I'm trying to write a function that will process a certain type of objects and call a certain method passed as one of the args. Since there's no inheritance or generics, I'm using embedding. (I can't use interfaces as you can only define methods in them, and I need struct fields as well).

I'm new at Go, so I'm definitely doing something wrong. Here's a simplified version of my code:

http://play.golang.org/p/r0mtDXtmWc

package main

import "fmt"
import "reflect"

type Animal struct {
    Type string
}

type Dog struct {
    Animal
}

type Cat struct {
    Animal
}

func (d *Dog) SayWoof() {
    fmt.Println("WOOF")
}

func (c *Cat) SayMeouw() {
    fmt.Println("MEOUW")
}

func CallMethod(animal interface{}, baseAnimal *Animal, methodName string) {
    fmt.Println("Animal type: ", baseAnimal.Type)

    method := reflect.ValueOf(animal).MethodByName(methodName)
    if !method.IsValid() {
        return
    }

    method.Call([]reflect.Value{})
}

func main() {
    dog := &Dog{}
    dog.Type = "Dog" // for some reason dog := &Dog{Type: "Dog"} doesn't compile

    cat := &Cat{}
    cat.Type = "Cat"

    CallMethod(dog, &dog.Animal, "SayWoof")
    CallMethod(cat, &cat.Animal, "SayMeouw")
}

output:

Animal type:  Dog
WOOF
Animal type:  Cat
MEOUW

This code works, but I basically need to pass an object twice: first an interface to call a method dynamically and then the embedded ("parent") object to get access to its fields.

I would much rather have something like

func CallMethod(animal Animal, methodName string)

but then if cast a Dog object to an Animal like this:

CallMethod(dog.Animal, "SayWoof")

it obviously won't work as there's no "SayWoof" method defined in Animal.

So the question is: is there a way to pass a child object to a function once and have access to all its reflection data?

Thanks

Upvotes: 0

Views: 313

Answers (1)

Seth Hoenig
Seth Hoenig

Reputation: 7397

package main

import "fmt"

type Animal interface {
    Speak()
}

type Dog struct {
}

type Cat struct {
}

func (d *Dog) Speak() {
    fmt.Println("Woof")
}

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

func Speaketh(a Animal) {
    a.Speak()
}

func main() {
    dog := Dog{}
    cat := Cat{}
    Speaketh(&dog)
    Speaketh(&cat)
}

How exactly would you expect a language with generics to solve your problem anyway? That's an honest question. With different function names you want to call "SayMeow" and "SayWoof", no type agnostic data structure is going to help you magically call the right thing.

Upvotes: 1

Related Questions