Alex

OOP Concepts in Go (Videos 17-20)

An Overview

Methods and Interfaces

“An interface, which is something that can do something. Including the empty interface, which is something that can do nothing, which is everything, because everything can do nothing, or at least nothing.” - Brad Fitzpatrick

type Stringer interface {
  String() string
}
type ReadWriter interface {
  Reader
  Writer
}

Interface Declarations

type Bigger struct {
  otherpackage.Big // Struct composition to be explored later
}

func (b Bigger) SomeMethod() {

}

Composition in Go

type Host struct {
  Hostname string
  Port int
}

type SimpleURI struct {
  Host
  Scheme string
  Path string
}

func main() {
  s := SimpleURI{
		Host:   other.Host{Hostname: "google.com", Port: 8080},
		Scheme: "https",
		Path:   "/search",
	}

  fmt.Println(s.Hostname, s.Scheme) // See how the Host has been promoted
}
type Thing struct {
	Field string
}

func (t *Thing) bruh() {
	fmt.Println(t.Field)
}

// Would also be valid with a value receiver method
// func (t Thing) bruh() {
// 	fmt.Println(t.Field)
// }

type Thing2 struct {
	*Thing
	Field2 string
}

func main() {
	t := Thing2{&Thing{"Hello"}, "world"}
	t.bruh() // Method call here is valid
}

Composition with Sorting Example

type Interface interface {
  // The length of the collection
  Len() int
  // Says whether the element at index i is less than the element at index j
  Less(i, j int) bool
  // Swaps the element at index i with the element at index j in the collection
  Swap(i, j int)
}
type Component struct {
  Name string
  Weight int
}

type Components []Component

func (c Components) Len() int { return len(c) }
func (c Components) Swap() { c[i], c[j] = c[j], c[i] }
func (c Components) Less(i, j int) {
  // LT rather than the less than symbol because Jekyll
  return c[i].Weight LT c[j].Weight
}
type ByName struct{ Components }
func (bn ByName) Less(i, j int) bool {
  return bn.Components[i].Name LT bn.Components[j].Name
}

type ByWeight struct{ Components }
func (bw ByWeight) Less(i,j int) bool {
  return bn.Components[i].Weight LT bn.Components[j].Weight
}
type reverse struct {
  Interface // It just embeds sort.Interface
}

func (r reverse) Less(i, j int) bool {
  return r.Interface.Less(j, i) // Note swapped arguments for reverse sorting
}

func Reverse(data Interface) Interface {
  return &reverse{data}
}

Making Nil Useful

// The nil / zero value of this struct is ready to use since a nil slice can be appended to
type StringStack struct {
  data []string
}

func (s *StringStack) Push(x string) {
  s.data = append(s.data, x)
}

func (s *StringStack) Pop() string {
  l := len(s.data)

  if l == 0 {
    panic("pop from empty stack")
  }

  t := s.data[l-1]
  s.data = s.data[:l-1]
  return t
}
type IntList struct {
  Value int
  Tail *IntList
}

func (list *IntList) Sum() int {
  if list == nil {
    return 0
  }
  
  return list.Value + list.Tail.Sum()
}

Exploring Value / Pointer Method Semantics

type Thing struct{}

func (t Thing) ValMethod() {}
func (t *Thing) PointerMethod() {}

type IVal interface { ValMethod() }
type IPtr interface { PointerMethod() }

func main() {
  var t Thing

  var iVal IVal
  var iPtr IPtr

  iVal = t  // Valid
  iVal = &t // Valid

  iPtr = t  // Not valid, since the value t doesn't have the pointer method PointerMethod in it's method set
  iPtr = &t // Valid
}