Methods in Golang ( Golang methods )

Golang also supports methods similar to functions with a particular receiver type between the “func” keyword and the function name. The receiver can be of struct or a non-struct type.

In this post, we are going to look at below points –

Let’s look at all of the above points one by one.

How to declare a method?

Method declaration is almost similar to function declaration with only one difference. We must add one extra parameter in the method’s declaration, known as the receiver parameter. Like any other parameter, we have to provide the name of the receiver parameter along with its type.

Syntax of declaring a method

func (t type) func_name(parameter1_name parameter1_type, parameter2_name parameter2_type,...){
}
Method declaration in golang

Here, we can access t within the method’s body.

How to call a method from within the program?

First, we have to write the value on which we will use the method, the dot operator, and then the name of the method, followed by the parentheses. The value we’re calling the method on is the method receiver.

Calling a method in golang

We will use a struct type as a receiver type in our example. Let’s see how to call a method within a program.

package main

import (
	"fmt"
)

type Person struct {
	firstName string
	lastName  string
	age       int
	height    float64
}

func (p Person) displayAge() {
	fmt.Println("Person's age:", p.age)
}

func main() {
	var person Person
	person.firstName = "Codekru"
	person.lastName = "Website"
	person.age = 20
	person.height = 170.14

	person.displayAge() // calling the displayAge() method
}

Output –

Person's age: 20
Difference between methods vs. functions

Let’s see how to represent the above example using a function instead of a method.

If we are working with a function, we would have to pass the Person type as an argument, as shown in the program below.

package main

import (
	"fmt"
)

type Person struct {
	firstName string
	lastName  string
	age       int
	height    float64
}

func displayAge(p Person) {
	fmt.Println("Person's age:", p.age)
}

func main() {
	var person Person
	person.firstName = "Codekru"
	person.lastName = "Website"
	person.age = 20
	person.height = 170.14

	displayAge(person) // calling the displayAge() function
}

Why would we need methods if we can achieve the same functionality with functions?
  • Methods can have multiple methods of the same name and signature, provided that they belong to different receiver types, whereas functions with the same signature are not allowed. So, we can say that it is the Golang way of achieving method overloading, though it doesn’t support method overloading in a conventional sense.
package main

import (
	"fmt"
)

type Person struct {
	firstName string
	lastName  string
	age       int
	height    float64
}

type Animal struct {
	name   string
	age    int
	height float64
}

func (person Person) displayAge() {
	fmt.Println("Person's age:", person.age)
}

func (animal Animal) displayAge() {
	fmt.Println("Animal's age:", animal.age)
}

func main() {
	var person Person
	person.age = 20

	var animal Animal
	animal.age = 7

	person.displayAge() // calling the displayAge() method of person type
	animal.displayAge() // calling the displayAge() method of animal type
}

Output –

Person's age: 20
Animal's age: 7
  • Golang does not have classes and is not a pure object-oriented programming language. Methods in Golang are a way of achieving the functionality of classes. We can have different methods of the same type and can easily call them using the dot operator, just like calling the methods of a class.
Pointer receiver parameters

Now, what are pointer receiver parameters? But before knowing about it, let’s look at why we even need it?

We have worked with the value receiver parameters in our examples, but there is a limitation to value receivers. If any change is made within the method, those changes will not be reflected outside the method.

package main

import "fmt"

type Person struct {
	name string
	age  int
}

func (person Person) changeAge() {
	person.age = 25
}

func main() {
	var person Person
	person.age = 20

	fmt.Println("Age before calling the method:", person.age)

	person.changeAge() // calling the changeAge() method

	fmt.Println("Age after calling the method:", person.age)

}

Output –

Age before calling the method: 20
Age after calling the method: 20

Here, we have changed the person’s age from 20 to 25 within the method, but it wasn’t reflected outside the method. To overcome this situation, we can use the pointer receiver methods.

Pointer receiver methods have the receiver parameter of pointer type.

package main

import "fmt"

type Person struct {
	name string
	age  int
}

func (person *Person) changeAge() {
	person.age = 25
}

func main() {
	var person Person
	person.age = 20

	pointerToPerson := &person // pointer to the person variable

	fmt.Println("Age before calling the method", person.age)

	pointerToPerson.changeAge() // calling the changeAge() method

	fmt.Println("Age after calling the method", person.age)

}

Output –

Age before calling the method 20
Age after calling the method 25

Here, the person’s age change was also reflected outside of the function.

What if we call a pointer receiver method with direct value or vice versa?

Let’s try to look at this via an example.

package main

import "fmt"

type Person struct {
	name string
	age  int
}

func (person Person) valueReceiver() {
	fmt.Println("Value receiver method called")
}

func (person *Person) pointerReceiver() {
	fmt.Println("Pointer receiver method called")
}

func main() {
	var person Person
	pointer := &person

	person.valueReceiver()
	person.pointerReceiver() //value will be automatically converted to pointer

	pointer.valueReceiver() //value at pointer is automatically retrieved
	pointer.pointerReceiver()
}

Output –

Value receiver method called
Pointer receiver method called
Value receiver method called
Pointer receiver method called

So, in Golang, we can call a value receiver method with a pointer type and vice versa.

  • If we call a pointer receiver method with a value type receiver, it will automatically be converted to the pointer type.
  • And if we are calling a value receiver method with a pointer, then the value stored at the pointer will be automatically retrieved and be used while calling the value receiver.

Though there is one thing to keep in mind while using value to call a pointer receiver method

Go converts the values to pointers only if the value is stored in a variable. If we try to call the pointer receiver method on the value itself, then Go will give an error.

person := Person{age: 20}
person.pointerReceiver() // using a variable

It is correct and will not give any error

// Calling pointerReceiver on the value itself
Person{age: 20}.pointerReceiver()

This will give the below error

cannot call pointer method on Person{...}
Calling methods on a type defined in an another package

We cannot call a method on a type defined in a different package. To call a method, the definition of the method and the type must be in the same package.

package main

func (i int) valueReceiver() {
}

func main() {

}

The above code will give you the below error.

cannot define new methods on non-local type int

Now, we have to create our type if we want to work on the types defined in some other package. So, let’s make our type which will be kind of a wrapper on the int data type.

package main

import "fmt"

type integer int // creating our own integer type

func (i integer) valueReceiver() {
	fmt.Println("Value of i:", i)
}

func main() {

	i := integer(3)

	i.valueReceiver()

}

Output –

Value of i: 7

In the same way, we can call the method on non-struct types.

We hope that you have liked the article. If you have any doubts or concerns, please feel free to write us in the comments or mail us at [email protected].

Liked the article? Share this on

Leave a Comment

Your email address will not be published. Required fields are marked *