Go inheritance
In object-oriented programming (OOP), inheritance is a mechanism that allows a class (subclass) to inherit attributes and methods from another class (parent class). Through inheritance, subclasses can reuse the parent class's code, and can extend or modify their behavior without modifying the parent class.
Go is not a traditional object-oriented programming language; it does not have classes or inheritance.
Go uses structs and interfaces to implement similar functionality.
"Inheritance" in Go
The Go language lacks the class and inheritance concepts found in traditional object-oriented languages; instead, it uses composition and interfaces to achieve similar functionality.
Composition
Composition is the primary way Go implements code reuse. By embedding one struct into another, the child struct can "inherit" the fields and methods of the parent struct.
Example
import "fmt"
// Parent struct
type Animal struct {
Name string
}
// Parent struct's method
func (a *Animal) Speak() {
fmt.Println(a.Name, "says hello!")
}
// Child struct
type Dog struct {
Animal // Embed Animal struct
Breed string
}
func main() {
dog := Dog{
Animal: Animal{Name: "Buddy"},
Breed: "Golden Retriever",
}
dog.Speak() // Call the parent struct's method
fmt.Println("Breed:", dog.Breed)
}
Code Explanation
Animalis the parent struct, containing one fieldNameand a methodSpeak。Dogis the child struct, through embeddingAnimalThe struct inheritsAnimalthe fields and methods of.- In
mainIn the function, we created aDogan instance, and calledSpeakmethod.
2. Interface
Interfaces are the primary way Go implements polymorphism. By defining interfaces, different structs can implement the same methods, thereby achieving polymorphic behavior similar to inheritance.
Example code
Example
import "fmt"
// Define interface
type Speaker interface {
Speak()
}
// Parent struct
type Animal struct {
Name string
}
// Implement interface methods
func (a *Animal) Speak() {
fmt.Println(a.Name, "says hello!")
}
// Child struct
type Dog struct {
Animal
Breed string
}
func main() {
var speaker Speaker
dog := Dog{
Animal: Animal{Name: "Buddy"},
Breed: "Golden Retriever",
}
speaker = &dog
speaker.Speak() // Call the method through the interface
}
Code Explanation
Speakeris an interface, defining aSpeakmethod.AnimalThe struct implementsSpeakerInterface.DogThe struct, through embedding,Animalstruct, indirectly implementingSpeakerInterface.- In
mainIn the function, we willDogassign the instance toSpeakerinterface, and called through the interfaceSpeakmethod.
Differences between Go and classical inheritance
| Features | Classical inheritance | the Go way |
|---|---|---|
| Code Reuse | Through inheritance | Through composition (embedding structs) |
| Polymorphism | Through inheritance and method overriding | implemented through interfaces |
| Relationship | "is-a" relationship | "has-a" or "implements" relationship. |
| Flexibility | The inheritance relationship is fixed | can be composed at runtime |
Complete inheritance simulation:
Example
import "fmt"
// Base class
type Vehicle struct {
Brand string
}
func (v *Vehicle) Start() {
fmt.Println(v.Brand, "started")
}
// Derived class
type Car struct {
Vehicle // Embed Vehicle
Model string
}
// Override Start method
func (c *Car) Start() {
fmt.Println(c.Brand, c.Model, "car started")
}
func main() {
v := Vehicle{Brand: "Toyota"}
c := Car{
Vehicle: Vehicle{Brand: "Honda"},
Model: "Civic",
}
v.Start() // Toyota started
c.Start() // Honda Civic car started
c.Vehicle.Start() // Honda started
}
This design in Go avoids many problems of traditional inheritance, such as the fragile base class problem, while providing greater flexibility.
other extensions