Methods in Go

Methods in Go

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

Methods in Go

Go methods are similar to the 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 be present in the same package.

So basically, when you attach a function to a type, that function becomes a method for that type. The method will have access to the receiver’s properties and can call the receiver’s other methods.

You cannot 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
}

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 can create a method with a non-struct type receiver as long as the type and the method definitions are present in the same package.

If they are present in different packages like int, string, etc., 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, to define a method on a receiver, we must define the receiver type in the same package.

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

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

Exported Method

Go doesn’t have any public, private or protected keyword. The only mechanism to control the visibility outside the package is using the capitalized and non-capitalized formats

  • Capitalized Identifiers are exported. The capital letter indicates that this is an exported identifier and is available outside the package.
  • Non-capitalized identifiers are not exported. The lowercase indicates that the identifier is not exported and will only be accessed within the same package.
Methods in Go

Scroll to top