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 trialAnthony Albertorio
22,624 PointsMy 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)
*/