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
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With