Method Receiver Value vs Pointer Pada Go

Method receiver di Go mirip dengan metode pada beberapa bahasa pemrograman berbasis objek. Namun, penulisan sintaksis di Go berbeda dengan bahasa pemrograman berbasis objek lainnya.

Kesalahan yang sering terjadi saat menggunakan method receiver adalah menggunakan pointer pada struct tanpa menggunakan pointer. Ada dua istilah di Go:

  • Value Receiver
  • Pointer Receiver

Value Receiver membuat salinan atau kopian dari data yang dilewatkan ke argumen sebuah fungsi. Data tersebut akan berada di memori dengan objek yang sama, tetapi dengan alamat memori yang berbeda. Artinya, perubahan yang dilakukan hanya berlaku di dalam fungsi tersebut. Data aslinya tidak berubah.

Sedangkan Pointer Receiver langsung menunjuk ke alamat memori aslinya. Data yang ada di memori langsung merujuk ke alamat data aslinya. Dengan demikian, setiap perubahan akan langsung mengubah data aslinya.

Mari kita coba praktikkan dengan menggunakan Value Receiver terlebih dahulu:

package main

import (
	"fmt"
)

type Person struct {
	Name string
	Age  int
}

func (p Person) ChangeName(name string) {
	p.Name = name
}

func main() {
	person := Person{"Rizki", 19}
	fmt.Println("Sebelum diubah:", person)

	person.ChangeName("Asep")
	fmt.Println("Setelah diubah:", person)
}

Fungsi ChangeName() akan mengubah nilai field Name dari struct Person yang telah dideklarasikan sebelumnya. Namun, data aslinya tidak berubah; yang berubah hanya di dalam fungsi ChangeName().

$ go run main.go
Sebelum diubah: {"Rizki", 19}
Setelah diubah: {"Rizki", 19}

Jika dilakukan debugging.

func (p Person) ChangeName(name string) {
	p.Name = name
	fmt.Println("Perubahan di dalam fungsi ChangeName():", p)
}
$ go run main.go
Sebelum diubah: {"Rizki", 19}
Perubahan di dalam fungsi ChangeName(): {Asep 19}
Setelah diubah: {"Rizki", 19}

Jika kita debug di dalam fungsi ChangeName(), maka nilainya berubah, tetapi tidak dengan data aslinya. Artinya, data tersebut berada di memori dengan objek yang sama, tetapi dengan alamat memori yang berbeda. Maka data tersebut diduplikasi dari objek aslinya.

Sedangkan jika kita menggunakan Pointer Receiver:

package main

import (
	"fmt"
)

type Person struct {
	Name string
	Age  int
}

// memberikan tanda asterisk pada struct
func (p *Person) ChangeName(name string) {
	p.Name = name
}

func main() {
	person := Person{"Rizki", 19}
	fmt.Println("Sebelum diubah:", person)

	person.ChangeName("Asep")
	fmt.Println("Setelah diubah:", person)
}

Fungsi ChangeName() di atas telah menggunakan Penerima Pointer dengan memberikan tanda asterisk pada metode struct. Berikut hasil outputnya:

$ go run main.go
Sebelum diubah: {Rizki 19}
Setelah diubah: {Asep 19} // data berubah

Ya, data aslinya juga berubah. Artinya, data yang berada di memori stack langsung merujuk ke alamat data aslinya. Data yang sudah ada langsung diubah pada alamat memori aslinya.

Jadi kapan menggunakan value receiver dan pointer receiver?

Gunakan value receiver jika memang tidak ingin melakukan modifikasi pada data struct dan gunakan pointer receiver jika memang jika ingin mengubah atau memodifikasi data structnya.