Sunday, August 9, 2015

Go Methods

Prerequisites for this post:

You must understand Functions, Structs and Pointers. Please read the following posts before you proceed:

What are Methods?

Like functions, methods facilitate code reuse and are declared using func keyword. 

What is the difference between a Function and a Method?

A function with a receiver is a method. 

All methods are functions. But all functions might not be termed as methods.


package main

import "fmt"

type shape struct {
      l, w int
}

func (s shape) area() int { //value type receiver
      return s.l * s.w
}

func main() { 
 
     r := shape{11, 7}
     fmt.Println(r.area())
}

Play with the above code

In the above example the method area() is defined on the struct named shape. This might give you an impression that you can define a method only on struct. This is not true. You can define a method on any type you've defined in your package. However, you cannot define a method on a type from another package (including built in types).

Important: In the above code we have used (s shape) as a value type receiver.

Why is it better to have Pointer Receivers in Methods?


In Go, whenever we call a function that accepts an argument, the argument is copied to the function. Go passes everything by value. In the above example, the method named area() has value type shape as method receiver.


There are two specific reasons why a pointer receiver is recommended over a value type receiver.

1. With every method call the value is getting copied. Let us assume the struct contains many fields with large data sets. What happens if you're trying to copy this large struct? This is inefficient and the detrimental to code performance. In contrast to the value type receiver, a pointer receiver is extremely lightweight (4 or 8 bytes) as only the pointer (a reference i.e. an address) is copied and not the entire value. 

2. you must use a pointer in cases where a method can modify the value that its receiver points to.

Keeping the above discussion in mind, let us rewrite the above code using a pointer receiver:


package main

import "fmt"


type shape struct {
     l, w int
}

func (s *shape) area() int { //pointer receiver
     return s.l * s.w
}

func main() { 
 
   r := &shape{11, 7}
   fmt.Println(r.area())
}

Play with the above code

Why you must use pointer receiver?

In cases where the method doesn't modify the receiver value, we've a choice whether to define the method receiver as a value type or pointer. The experts recommend:

As a thumb rule, except for small structs and slices, always go for a pointer receiver, because it's great for performance.

Did this help you? If yes, feel free to share it.




No comments:

Post a Comment