Go language does not have the concept of a class directly. It, however, has a concept of an interface
as well as a struct
. I’ll illustrate how this can be used to build most of the inheritance constructs that a language like Java or C++ offers.
Inheritance#
I’ll use the cliché example of a Rectangle
class and a Square
class that inherits from it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| package main
import "errors"
// Rectangle encapsulates a immutable rectangle
type Rectangle struct {
width int32
height int32
}
// NewRectangle is the constructor of Rectangle
func NewRectangle(width int32, height int32) (*Rectangle, error) {
if width <= 0 {
return nil, errors.New("width must be > 0")
}
if height <= 0 {
return nil, errors.New("height must be > 0")
}
return &Rectangle{width, height}, nil
}
// Width returns the width
// Guaranteed to be a positive number
func (r Rectangle) Width() int32 {
return r.width
}
// Height returns the height
// Guaranteed to be a positive number
func (r Rectangle) Height() int32 {
return r.height
}
func (r Rectangle) Area() int64 {
return int64(r.width) * int64(r.height)
}
|
And the cliché Square
class that inherits from it
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| package main
// Square struct embeds Rectangle struct
// It gets all methods like Width() and Height() of the parent class
// for free
type Square struct {
Rectangle
}
// NewSquare is the constructor for the Square1 class
func NewSquare(side int32) (*Square, error) {
rect, err := NewRectangle(side, side)
if err != nil {
return nil, err
}
return &Square{*rect}, nil
}
|
Note: This all works fine, if the parent Rectangle class is immutable, however, if it is mutable, then it is better to use composition. However, that’s not a language-specific issue, so, worth discussing in a separate blog post about inheritance vs composition.
Implementation#
Go supports interfaces as well. But unlike Java or C++, no explicit declaration is required.
For example, consider a Shape
interface
1
2
3
4
5
6
| package main
type Shape interface {
// Area returns the area of the shape
Area() int64
}
|
Now, if one adds the following code to the Rectangle struct then both Rectangle and Square will be implementing the shape interface.
1
2
3
4
| // Area returns the area of the Rectangle
func (r Rectangle) Area() int64 {
return int64(r.width) * int64(r.height)
}
|
The complete example can be seen at https://go.dev/play/p/exbTybm0GGK