You might know methods from other programming languages like Java. In most cases, methods are functions, that are part of a class.

  • Go doesn’t have classes
  • Methods can be defined on types
  • A method has a special receiver argument
  • Receiver: Between funcand and method name
  • Still, methods are functions
func (v Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

In this case, Absmethod has receiver of type Vertexnamed v.

type Person struct {
	Name string
	Age  int
}
 
func (p Person) GreetPerson() {
	fmt.Println("Hello, my name is", p.Name)
}
 
func main() {
	//	defer fmt.Println("Hello, World!")
	max := Person{"Max", 25}
 
	max.GreetPerson()
}

Methods on non-struct types

In this case, not a struct but only a type:

 
type Person string
 
func (p Person) greetPerson() string {
	return "Hello, " + string(p)
}

Only types within the same package can be used

Pointer receivers

  • Methods
func (p Person) ChangeName() {
	p.Name = "John"
}
 
func main() {
	var max = Person{"Max", 23}
 
	max.ChangeName() // or: 
 
	fmt.Println(max.Name)
}

This doesn’t change the name of the person, as a copy is passed. Important: Keep in mind that max.ChangeName()is just syncatical sugar for ChangeName(max)if we were to rewrite the ChangeNamemethod slightly.

There, we need a way to change the value of the name actually: Using the memory address:

func (p *Person) ChangeName() {
	p.Name = "John"
}

By just adding a * in front, now a pointer is passed. Go automatically passes this pointer, but we can also manually pass it by: ChangeName(&max)or declaring it as a reference.

Rewritten to a function:

func ChangeNameFun(p *Person) {
	p.Name = "John"
}
 
func main() {
	var max = Person{"Max", 23}
 
	ChangeNameFun(&max)
 
	fmt.Println(max.Name)
}

The only difference when using a function instead a method for the change is that we now need to pass the reference. This is explained in the next section.

Methods and pointer indirection

  • Functions with a pointer parameter must take a pointer
  • Methods with a pointer receiver can take either a value or a pointer

The same is true vice versa:

  • Functions that expect a value, must receive a value of the type
  • Methods with value receives can handle either a value or a pointer

Use pointer receivers in two cases:

  • Accessing the value If you really direct need access to it, use a pointer receiver
  • Avoiding copying Using values instead of pointer receivers always copy the value into the method. For huge chunks of data, this takes time. Pointers are the smarter way.

Next chapter: make() and new()