Pelajaran modul (2/5)
Metode: nilai vs penerima penunjuk
Metode di Go adalah fungsi dengan penerima: spesial
parameter dideklarasikan antara func dan nama metode, yang mengikat
metode ke suatu tipe. Tidak ada kelas: metode dapat ditentukan
semua tipe bernama yang dideklarasikan dalam paket saat ini.
Sintaksis
type Person struct {
Name string
}
func (p Person) Greet() string {
return "ciao " + p.Name
}
p := Person{Name: "Ada"}
fmt.Println(p.Greet()) // "ciao Ada"Penerima p Person menjadikan Greet sebagai metode Person. Di dalam
metode, p adalah variabel seperti yang lainnya.
Penerima nilai vs penerima penunjuk
// VALUE receiver: operates on a COPY of the value
func (p Person) NameUpper() string {
return strings.ToUpper(p.Name)
}
// POINTER receiver: operates on the original value, can mutate it
func (p *Person) Rename(n string) {
p.Name = n
}Dengan penerima penunjuk Anda dapat memodifikasi penerima dan perubahannya terlihat di luar metode. Dengan penerima nilai Anda tidak bisa - Anda akan melakukannya hanya memodifikasi salinan lokal.
p := Person{Name: "Ada"}
p.Rename("Grace")
fmt.Println(p.Name) // "Grace" — change is visibleKapan menggunakan penerima penunjuk
Aturan praktis, berdasarkan prioritas:
- Anda harus memodifikasi penerima → penerima penunjuk. Wajib.
- Strukturnya besar (lusinan bidang, array di dalamnya) → penunjuk penerima untuk menghindari salinan yang mahal.
- Konsistensi: jika SETIDAKNYA satu metode pada tipe tersebut memiliki penerima penunjuk, gunakan penerima penunjuk untuk yang lain juga. Sebuah konvensi yang sangat penting untuk antarmuka (Modul 6).
- Tipe "nilai" yang kecil dan tidak dapat diubah (waktu.Waktu, bilangan kompleks, kecil struct) → penerima nilai, lebih mudah dibaca.
Metode pada tipe non-struct
Anda dapat mendefinisikan metode pada tipe NAMED apa pun yang dideklarasikan dalam paket Anda:
type Celsius float64
func (c Celsius) ToFahrenheit() float64 {
return float64(c)*9/5 + 32
}
t := Celsius(20)
fmt.Println(t.ToFahrenheit()) // 68Anda tidak dapat mendefinisikannya berdasarkan tipe dari paket lain (misalnya int, string): Anda harus
pertama-tama buat tipe bernama lokal.
Cobalah
Tambahkan metode string Greet() (penerima nilai) ke Person yang mengembalikan 'ciao <Nama>'.
Tunjukkan petunjuk
Penerima dalam tanda kurung SEBELUM nama metode.
Solusi tersedia setelah 3 upaya
Tambahkan metode Ganti Nama(n string) dengan penerima POINTER yang mengubah p.Nama.
Tunjukkan petunjuk
Penerima penunjuk: `(p *Orang)`.
Solusi tersedia setelah 3 upaya
Kapan sebaiknya Anda menggunakan penerima penunjuk (p *T)?
func (t ?T) M() { ... }Rekap
- Metode = fungsi dengan penerima:
func (r T) Name(...) ... { ... }. - Penerima nilai: beroperasi pada salinan; Penerima penunjuk: beroperasi pada aslinya.
- Go melakukan konversi
T↔*Tsecara otomatis di situs panggilan. - Penerima penunjuk ketika: mutasi + struct besar + konsistensi dengan metode sejenis lainnya.
- Jangan pernah mencampur penerima nilai dan penunjuk pada tipe yang sama.
- Metode menggunakan tipe NAMED dalam paket saat ini (termasuk non-struct).