Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Go Language Go Language Overview Custom Types Methods

My notes on Methods- explains receivers, methods with parameters, methods with a variable amount of parameters.

package main

import (
    "fmt"
    "strings"
)

type Title string // Custom type


// as function
func FixCase(t Title) string {
  return strings.Title(string(t))  // convert Title value to string
} 

// as method- notice parameter before Method name. Thats it really.
func (t Title) FixCase() string {  // declare method, no arguments except reciever parameter
  return strings.Title(string(t))  // convert Title value to string
}

type MyType float64

func (m MyType) MyMethod() {
  fmt.Println("In MyMethod on MyType")
}

type Minutes int

func (m Minutes) Increment() {  // pass by value. manipulating copy. won't update
  m = (m + 1) % 60
}

func (m *Minutes) IncrementWithPointer() {  // pass by reference. manipulating original. will update
  *m = (*m + 1) % 60
}

// methods that take parameters
type myInt int  // create custom type

func (a myInt) add(b myInt) myInt {  // create method with parameters and receiver
  return a + b
}

func (a *myInt) addWithPointer(b myInt) myInt {  // create method with parameters and receiver
  return *a + b
}

// can take variable amount of arguments aka variadic functions
func (a myInt) sumAll(b ...myInt) myInt {  // ... expansion operator turns variables into list.
  sum := myInt(0)
  for i := range b {
    sum += b[i]
  }
  return a + sum
}



func main() {
  movieName1 := Title("the matrix")
  fixedMovieName1 := FixCase(movieName1)
  fmt.Println(fixedMovieName1)

    movieName := Title("the matrix")       // Title value as argument
  fixedMovieName := movieName.FixCase()  // calls method.
  fmt.Println(fixedMovieName)

  myValue := MyType(1.23)  // sets 1.23 as value for custom type
  myValue.MyMethod()       // call method

  // pointers and methods
  minutes := Minutes(58)

  for i := 1; i <= 3; i++ {
    minutes.Increment()
    fmt.Println(minutes)
  }

  for i := 1; i <= 3; i++ {
    minutes.IncrementWithPointer()  // updates in memory via pointers
    fmt.Println(minutes)
  }

  // methods that take parameters
  num1 := myInt(1)
  num2 := myInt(2)
  sum := num1.add(num2)  // func sig: (a MyInt) add (b MyInt) == var1.method(var2)
  fmt.Println("Sum is:", sum)

  // using pointers
  numA := myInt(1)
  numB := myInt(2)
  sumPointers := numA.addWithPointer(numB)
  fmt.Println("numA is:", numA)
  fmt.Println("Sum with pointers", sumPointers)

  numA = numA.addWithPointer(numB)
  fmt.Println("numA is:", numA)

  // using variable amount of parameters
  num3, num4, num5 := myInt(3), myInt(4), myInt(5)

  sumOfAll := num1.sumAll(num2, num3, num4, num5)

  fmt.Println("sum of all: ", sumOfAll)
}

/*
Notes:
Simply:
Methods are just like functions except for they parameter in front of method name. Thats it.
Receiver parameter links functions to their associated types or structs.
They are just an extra set of parameters before the function name.

Receiver is the instance variable. They receive message from method when called.
Receiver calls method. It gets back something. So instance receives from function.
Hence name.

Receiver parameter in function signature tells function where to send message back.

Why is this needed?
There is no self or this keyword like Python or JavaScript
Thats really it. The Go docs make it seem more complicated than what it is.


Methods- function with special reciever argument
         Allows you to define new behaviors for values of a type/struct

reciever- The instance calling the function. They receive info back from function.
reciever parameter- Special parameter signature before method name (see below)
                    The method needs to know where to send message back
                    after instance calls, since there is no "self" or "this" keywords 

Why use the reciever?
It tells compiler to what Type or Struct the function is connected to.

Compiler looks at the receiver type, then calls method connected to type.

func (m Minutes) Increment() {  // m  parameter for sampleInstance 
  ...                           // Minutes is instance Type
}

sampleInstance := Minutes(15)  // set instance
sampleInstance.Increment()     // call method on instance

Receiver Type: Minutes.
Receiver: sampleInstance
Reciever parameter: (m Minutes)

with pointers:
func (m *Minutes) Increment() {
   ...
}

Convention: 
Reciever parameter is lower case letter of type or struct.
func (m Minutes)
func (t Title)

func (x XType) SampleMethod() returnType { - declare method (pass by value)
  ...
}

instance1.SampleMethod() - called like


func (x XType) SampleMethod()  { - declare method without return type (pass by value)
  ...
}

instance1.SampleMethod() - called like


func (x *XType) SampleMethod() returnType { - declare method with pointer (pass by reference)
  ...
}

instance1.SampleMethod() - called like. Same as above


func (x XType) SampleMethod(a XType, b XType) returnType { declare method with 2 variable args
  ...
}

instance1.SampleMethod(instance2, instance3) - called like


func (x XType) SampleMethod(a ...XType) returnType { - declare method with variable args
  ...
}

instance1.SampleMethod(instance2, instance3, instanceN) - called like


calling methods for pointers
(&variableX).MethodForPointer - Don't do this. Works for pointers, but not idiomatic
variableX.MethodForPointer  - Do this. auto-converts for pointer methods, so let it. Idiomatic.

Can't pass values-receiver based values to pointer-receiver based methods.

Don't confuse the dot notation for calling a method
with dot notation for calling a function exported from package
They are NOT the same thing.

From Docs:
equivalent statements
SampleStruct.MethodNameValue(7) - calling method
SampleStruct.MethodNameValue(sampleInstance, 7)
(SampleStruct).MethodNameValue(sampleInstance, 7)

under the hood:
f := SampleType.MethodNameValue is invoked as f(sampleInstance, 7) not sampleInstance.f(7)

*/