mdawar.dev

A blog about programming, Web development, Open Source, Linux and DevOps.

Go - Methods

A method is a function with a special receiver parameter.

Declaration

  • Methods can be defined on types that are defined in the same package
  • They cannot be defined for built-in types or types in other packages
  • The receiver associates the method with the receiver’s base type
  • The receiver is specified with a parameter preceding the method name
  • The receiver must be a type or a pointer to a type
go
// By convention a single letter is used for the receiver's parameter.
func (r ReceiverType) MethodName() {
  // Method implementation
}

Value Receiver

go
package main

import "fmt"

// A custom type.
type MyInt int

// Go does not have classes, however we can define methods on types.
// When using a value receiver a copy is passed.
// A value receiver is used when the method doesn't modify the value.
func (i MyInt) Square() int {
  return int(i * i) // Convert MyInt to int
}

func main() {
  var n MyInt = 2

  fmt.Println(n) // 2

  // Call a method.
  squared := n.Square()

  fmt.Println(squared) // 4

  // A pointer to the variable.
  p := &n // *MyInt

  // A method with a value receiver can be called on a pointer.
  p.Square()
  // Equivalent to
  (*p).Square()
}

Pointer Receiver

go
package main

import "fmt"

type MyInt int

// A pointer receiver allows the method to modify the receiver's value.
// It can also be used for performace optimization to avoid copying a large value
// on each method call even if the method does not modify the receiver.
func (i *MyInt) Increment() {
  *i++ // Modify the value
}

// For consistency if a method uses a pointer receiver we define
// all the other methods too with a pointer even if they don't modify the value.
func (i *MyInt) Square() int {
  return int(*i * *i) // Convert MyInt to int
}

func main() {
  var n MyInt

  fmt.Println(n) // 0 (zero value)

  // Call a method that modifies the value.
  // Methods with a pointer receiver can be called with a value or a pointer.
  n.Increment()
  // Equivalent to
  (&n).Increment()

  fmt.Println(n)          // 2 (incremented twice)
  fmt.Println(n.Square()) // 4
}

Method Value & Expression

go
package main

import "fmt"

type MyInt int

// Method with value receiver.
func (i MyInt) Square() int {
  return int(i * i)
}

// Method with pointer receiver.
func (i *MyInt) Increment() {
  *i = *i * 2
}

func main() {
  a := MyInt(4)

  // A method value is created by referencing a method
  // on a specific instance of a type.
  square := a.Square // Method value

  // A method value captures the receiver value.
  // It allows calling the method without specifying the receiver.
  fmt.Println(square()) // 16

  // A method expression is created by referencing a method on a type.
  Square := MyInt.Square // Method expression

  // A method expression converts the method into a function
  // that takes the receiver as its first argument.
  // It allows using the method as a general function with
  // different receiver values.
  fmt.Println(Square(a)) // 16

  increment := a.Increment        // Method value
  Increment := (*MyInt).Increment // Method expression

  increment()    // Equivalent to a.Increment()
  fmt.Println(a) // 5

  Increment(&a)  // Equivalent to (&a).Increment()
  fmt.Println(a) // 6
}