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.