Go - Method Sets and Interfaces

Contemporary Programming Languages - CS2001 - 16 November 2017

Methods and Packages

  • A method can only be defined for types declared in the same package
    • Writing a method for a type in mypackage? The receiver type must be defined in the same package as the method (mypackage)
  • Method receivers cannot be an interface type.

Interface Types

  • An Interface is a type that defines a set of methods.
  • You implement an interface by implementing all of its methods.
    • A variable of interface type can store a value of any type with a method set that is a superset of that interface.
    • Usually named ____er
    • The zero-value is nil
      var i Stringer
      

Method Sets

  • The method set of an interface type is an interface
  • The method set of any other type T consists of all methods defined with receiver type T
  • The method set for *T is the set of all methods defined with receiver type T or *T
    • So, the method set for *T contains the members of the method set for T
type Dog struct {
  stomach []string
}
func (d *Dog) Eat(food string) {
  d.stomach = append(d.stomach, food)
}

type Cow struct {
  stomachs [4][]string
}
func (c *Cow) Eat(food string) {
  c.stomachs[0] = append(c.stomachs[0], food)
}

type Eater interface {
  Eat(string)
}
func FeedCorn(e Eater) {
  e.Eat("corn")
}

func main() {
  d := Dog{}
  c := Cow{}
  d.Eat("spaghetti") // {["spaghetti"]}
  c.Eat("sandwich") // {[["sandwich"][][][]]}
  var e Eater
  e = &d
  e.Eat("kale")
  e = &c
  e.Eat("spinach")
  FeedCorn(&d)
  FeedCorn(&c)
  FeedCorn(e)
}
// in fmt
type Stringer interface {
  String() string
}

// in sort
type Interface interface {
  Len() int
  Less(i, j int) bool
  Swap(i, j int)
}

using a stringer to print the string of a variable

var r Result
fmt.Println(r)
type Pony struct {
  Name string
  Height, Weight float64
  Foods []string
}
func (p Pony) String() string {
  return fmt.Sprintf("%s (%f)", p.Name, p.Weight)
}

type Ponies []Pony
func (ps Ponies) Len() int {
  return len(ps)
}
func (ps Ponies) Less(i, j int) bool {
  return ps[i].Weight < ps[j].Weight
}
func (ps Ponies) Swap(i, j int) {
  ps[i], ps[j] = ps[j], ps[i]
}

func main() {
  ranch := make(Ponies, 100)
  for i := range ranch {
    ranch[i].Name = fmt.Sprintf("p%i")
    ranch[i].Weight = float64(i%3)
  }
  fmt.Println(ranch) // [p0(0.00) p1(1.00) ...]
  sort.Stable(ranch)
  fmt.Println(ranch) // [p0(0.00) p3(0.00) ...]
}

Empty Interface

  • The interface type that specifies zero methods.
  • Every type implements empty interface because every type has at least zero methods in its method set.
interface{}
func main() {
  var i interface{}
  fmt.Println(i)
  i = 5
  describe(i)
}
func describe(thing interface{}) {
  fmt.Printf("%v;%T ln", thing, thing)
}
var i interface{} = "hello"
s := i.(string) // not a method, a language feature
fmt.Println(s) // hello
// f := i.(float64) // panic
f, ok := i.(float64) // fine, no panic
switch v := i.(type) {
case int:
  // v is an int
case string:
  // v is a string
default:
  // v is empty interface
}