Imperatives #
Golang is an imperative language, so the following flies:
package main
import (
"fmt"
"math"
)
type shape interface {
area() float64
}
type rectangle struct {
width float64
height float64
}
func (r rectangle) area() float64 {
return r.width * r.height
}
type circle struct {
radius float64
}
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func printArea(shape shape) {
fmt.Println(shape.area())
}
func main() {
printArea(rectangle{width: 10, height: 5})
printArea(circle{radius: 10})
}
50
314.1592653589793
One of the neat things about this is that any struct that fulfills the contract automatically “extends” the interface. Among other things, this makes mocking dependency types really easy.
Embedding #
If you want to “extend” a struct in Go, you can use embedding
Go does not provide the typical, type-driven notion of subclassing, but it does have the ability to “borrow” pieces of an implementation by embedding types within a struct or interface.
package main
import "fmt"
type worker struct {
}
func (w *worker) work() {
fmt.Println("I am working!")
}
type leech struct {
worker
}
func main() {
leecher := leech{}
leecher.work()
}
I am working!
This also works for interfaces:
package main
type worker interface {
work()
}
type leech interface {
worker
}