Methods

2-minute read
Table of Contents

In Go, we can attach methods (functions) onto structs to make them behave like objects in other languages.

Objects own data (they have variables) and perform actions (they have functions).

Each method has a receiver type which is the type of the struct:

package main

import "fmt"

type person struct {
	name      string
	age       int
	xPosition int
	yPosition int
}

func (p *person) describeYourself() {
	fmt.Printf("My name is %s. I am %d years old.\nYou can find me at coordinates (%d, %d).\n", p.name, p.age, p.xPosition, p.yPosition)
}

func (p *person) moveTo(x, y int) {
	p.xPosition = x
	p.yPosition = y
	fmt.Printf("Moving %s to (%d, %d)...\n", p.name, x, y)
}

func main() {
	me := person{name: "James", age: 34}
	me.describeYourself()

	me.moveTo(3, 4)
	me.describeYourself()
}
methods.go
Copy

Pointer receiver type vs. normal receiver type

We can also use the normal receiver type person instead of the pointer receiver type *person:

package main

import "fmt"

type person struct {
	name      string
	age       int
	xPosition int
	yPosition int
}

func (p person) describeYourself() {
	fmt.Printf("My name is %s. I am %d years old.\nYou can find me at coordinates (%d, %d).\n", p.name, p.age, p.xPosition, p.yPosition)
}

func (p person) moveTo(x, y int) {
	p.xPosition = x
	p.yPosition = y
	fmt.Printf("Moving %s to (%d, %d)...\n", p.name, x, y)
}

func main() {
	me := person{name: "James", age: 34}
	me.describeYourself()

	me.moveTo(3, 4)
	me.describeYourself()
}
methods-alt.go
Copy

The pointer receiver type *person is preferable over receiver type person as this avoids copying on method calls and allows the method to mutate the receiving struct:

package main

import "fmt"

type person struct {
	name string
	age  int
}

func (p person) changeName(newName string) {
	p.name = newName
}

func (p *person) changeNameByPointer(newName string) {
	p.name = newName
}

func personInfo(p person) {
	fmt.Printf("My name is %s. I am %d years old.\n", p.name, p.age)
}

func main() {
	person1 := person{"John", 12}
	person2 := person{"Mary", 17}

	personInfo(person1)
	personInfo(person2)

	person1.changeName("David")
	person2.changeNameByPointer("Lisa")

	personInfo(person1)
	personInfo(person2)
}
methods-mutate.go
Copy

Notice that the changeName method used by the person1 struct named John is unable to change its name field. The changeNameByPointer method is however able to change the name field of the underlying struct person2 with the initial name Mary.

Methods when combined with interfaces in Go produce the repository pattern which allows us to swap out completely unrelated structs as long as they implement the same methods e.g. if both person and animal structs have a moveTo method, they can be used interchangeably for different results in our program.

Support us via BuyMeACoffee