Some quick notes on Go after taking a short “OOP in Go” course from LinkedIn (instructor Frank P Moley III).
Encapsulation
Encapsulation in Go is performed at a package level and controlled by the case of the first letter of a symbol. Lower cased symbols are protected in the package and upper cased symbols are public. This applies equally to properties in a struct as well as function/methods.
A class is implemented as a struct. Instance methods can be implemented by a function with a weird syntax:
type Person struct {
...
name string
}
func (p Person) Greet() string {
// This would be an instance method off of Person.
// If Person is a large struct, it may be better to use "func (p *Person)."
// But that will be a topic in another post.
return fmt.Sprintf("%s says Hello", p.name)
}
...
func f(person Person) {
van := Person { name: "Van" }
fmt.Println(person.Greet()) // "Van says Hello"
}
Inheritance
Inheritance is achieved via composition of a struct inside another. Simply adding a struct as a property of another struct merges the first struct into the second (outer) struct.
type Runnable interface {
Run() string
}
type Person struct {
name string
Runnable // anonymous property of type Runnable, not a typeless property named Runnable
}
...
func (p Person) Run() string {
return fmt.Sprintf("%s is indeed running", p.name)
}
func GetRunning(r Runnable) string {
return r.Run()
}
...
van := Person { name: "Van" }
fmt.Println(GetRunning(van)) // "Van is indeed running"
Also illustrated is how Person is polymorphically attached to Runnable. Another type can do the same thing and implement its own Run(). Then that type (as is Person) can now be treated as a Runnable.