Methods in Go

Methods in Go

In this tutorial, we are going to discuss about methods in Go language.

Go methods are similar to Go function with one difference, i.e, the method contains a receiver argument in it. With the help of the receiver argument, the method can access the properties of the receiver.

The receiver argument has a name and a type. It appears between the func keyword and the method name.

func (receiver Type) MethodName(parameterList) (returnTypes) { } 

The receiver can be of struct type or non-struct type. When you create a method in your code the receiver and receiver type must present in the same package.

You are not allowed to create a method in which the receiver type is already defined in another package including inbuilt type like int, string, etc. If you try to do so, then the compiler will give an error.

package main

import (
    "fmt"
)

type Employee struct {
    name   string
    age    int
    salary int
}

/*
 displayDetails() method has Employee as the receiver type
*/
func (e Employee) displayDetails() {
    fmt.Println("Name : ", e.name)
    fmt.Println("Salary : ", e.salary)
    fmt.Println("Age : ", e.age)
}

func main() {
    emp := Employee{
        name:   "Ashok Kumar",
        salary: 50000,
        age:    29,
    }
    emp.displayDetails()
}

Output

Name :  Ashok Kumar 
Salary :  50000 
Age :  29

Run in playground

In Go language, you are allowed to create a method with non-struct type receiver as long as the type and the method definitions are present in the same package.

If they present in different packages like int, string, etc, then the compiler will give an error because they are defined in different packages.

package main

import "fmt"

type data int

func (d1 data) multiply(d2 data) data {
    return d1 * d2
}

/*
// if you try to run this code, then compiler will throw an error
func (d1 int) multiply(d2 int) int {
    return d1 * d2
}
*/

func main() {
    value1 := data(10)
    value2 := data(20)
    res := value1.multiply(value2)
    fmt.Println("Final result : ", res)
}

Output

Final result :  200

Run in playground

Methods vs Functions

The above struct type program can be rewritten using only functions and without methods.

package main

import (
    "fmt"
)

type Employee struct {
    name   string
    age    int
    salary int
}

/*
displayDetails() method converted to function with Employee as parameter
*/
func displayDetails(e Employee) {
    fmt.Println("Name : ", e.name)
    fmt.Println("Salary : ", e.salary)
    fmt.Println("Age : ", e.age)
}

func main() {
    emp := Employee{
        name:   "Ashok Kumar",
        salary: 50000,
        age:    29,
    }
    displayDetails(emp)
}

Output

Name :  Ashok Kumar 
Salary :  50000 
Age :  29

Run in playground

In the program above, the displayDetails method is converted to a function and the Employee struct is passed as a parameter to it. This program also produces the exact same output.

So why do we have methods when we can write the same program using functions. There are a couple of reasons for this. Let’s look at them one by one.

1. Go is not a pure object-oriented programming language and it does not support classes. Methods help you write object-oriented style code in Go. Method calls are much easier to read and understand than function calls.

2. Methods with the same name can be defined on different types whereas functions with the same names are not allowed. Let’s assume that we have a Square and Circle structure. It’s possible to define a method named Area on both Square and Circle. This is done in the program below.

package main

import (
    "fmt"
    "math"
)

type Rectangle struct {
    length int
    width  int
}

type Circle struct {
    radius float64
}

func (r Rectangle) Area() int {
    return r.length * r.width
}

func (c Circle) Area() float64 {
    return math.Pi * c.radius * c.radius
}

func main() {
    r := Rectangle{
        length: 10,
        width:  5,
    }
    fmt.Println("Area of rectangle : ", r.Area())
    c := Circle{
        radius: 12,
    }
    fmt.Println("Area of circle : ", c.Area())
}

Output

Area of rectangle :  50 
Area of circle :  452.3893421169302
Difference Between Method and Function
Methods with Pointer receivers

All the examples that we saw in the previous sections had a value receiver.

With a value receiver, the method operates on a copy of the value passed to it. Therefore, any modifications done to the receiver inside the method is not visible to the caller.

// Method with pointer receiver 
func (receiver *Type) MethodName(parameterList) (returnTypes) { 
} 

Methods with pointer receivers can modify the value to which the receiver points. Such modifications are visible to the caller of the method as well.

package main

import (
    "fmt"
)

type Employee struct {
    name string
    age  int
}

func (e Employee) changeName(newName string) {
    e.name = newName
}

func (e *Employee) changeAge(newAge int) {
    e.age = newAge
}

func main() {
    e := Employee{
        name: "Ashok Kumar",
        age:  28,
    }
    fmt.Println("Employee name before change : ", e.name)
    e.changeName("Ashok")
    fmt.Println("Employee name after change : ", e.name)

    fmt.Println("Employee age before change : ", e.age)    
    e.changeAge(29) 
    fmt.Println("Employee age after change : ", e.age)
}

Output

Employee name before change :  Ashok Kumar 
Employee name after change :  Ashok Kumar 
Employee age before change :  28 
Employee age after change :  29

Run in playground

Method definition restrictions

Note that, For you to be able to define a method on a receiver, the receiver type must be defined in the same package.

Go doesn’t allow you to define a method on a receiver type that is defined in some other package (this includes built-in types such as int as well).

In all the previous examples, the structs and the methods were defined in the same package main. Therefore, they worked. However, if you try to define a method on a type defined in some other package, the compiler will complain.

Methods in Go


Scroll to top