Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go "inheritance" - using anonymous type in a struct as a method parameter

Tags:

inheritance

go

I'm trying to firm up the concept of inheritence that Go provides (rather "composition" than pure inheritence, perhaps). However, I'm failing to grasp why I can't use the "parent" type as a func parameter to produce a generic function that acts on the parameter.

package main

import "log"

type Animal struct {
    Colour string
    Name string
}

type Dog struct {
    Animal
}

func PrintColour(a *Animal) {
    log.Printf("%s\n", a.Colour)
}


func main () {
    a := new (Animal)
    a.Colour = "Void"
    d := new (Dog)
    d.Colour = "Black"

    PrintColour(a)
    PrintColour(d)
}

Assuming my understanding's incorrect, how can I achieve what I want in Go?

Edit Note:

  • I don't want to attach the behaviour to the struct

  • I'd like to keep the pointer type as the method parameter because I'm working separately on a pet project and this requires I manipulate the struct passed in before then acting on it.

  • In reality my Dog struct would have additional fields/members; hopefully this doesn't muddy the water further

like image 389
Alex Avatar asked Feb 03 '14 12:02

Alex


People also ask

How do you inherit a struct in Go?

Since Golang does not support classes, so inheritance takes place through struct embedding. We cannot directly extend structs but rather use a concept called composition where the struct is used to form other objects. So, you can say there is No Inheritance Concept in Golang.

What is anonymous fields in Go struct?

Go allows you to define a struct that has fields but with no variable names. These fields are called anonymous fields. Let's do a few examples to find out what they are and how they will be useful. In the below example, we have defined a Kitchen struct, which only contains the number of plates as a field.

What is Golang composition?

Composition is a method employed to write re-usable segments of code. It is achieved when objects are made up of other smaller objects with particular behaviors, in other words, Larger objects with a wider functionality are embedded with smaller objects with specific behaviors.


1 Answers

I like the answers here so far and I want to add one that allows you to do static type checking on the interface you pass in using an interface:

package main

import (
    "fmt"
)

type Animalizer interface {
    GetColour() string
}

type Animal struct {
    Colour string
    Name   string
}

type Dog struct {
    Animal
}

func (a *Animal) GetColour() string {
    return a.Colour
}

func PrintColour(a Animalizer) {
    fmt.Print(a.GetColour())
}

func main() {
    a := new(Animal)
    a.Colour = "Void"
    d := new(Dog)
    d.Colour = "Black"

    PrintColour(a)
    PrintColour(d)
}

On the playground

It will be possible to add further fields to Dog. The difference to Uriel's Answer is that calls to PrintColour will fail at compile time if something else than a struct implementing Animalizer is passed in.

Also you won't have to use a typeswitch since the compiler knows an Animalizer is implementing GetColour.

And, finally, the behaviour (printing) is separated from the struct, GetColour just returns the colour.

like image 175
Beat Richartz Avatar answered Nov 07 '22 22:11

Beat Richartz