Fungsi Go — Go

Fungsi di Go Fungsi adalah blok kode yang bisa dipanggil berulang kali. Di Go, fungsi dideklarasikan dengan keyword func. Sintaks Dasar func namaFungsi(param1…

Fungsi adalah potongan kode yang diberi nama, menerima nilai masuk, dan bisa mengembalikan hasil. Bayangin dapur Warung Bakso Mas Bimo. Kasir menyerahkan slip "Bakso urat, Rp15.000, 3 porsi", dapur menghitung dan memasak, lalu mengembalikan satu nampan. Dapur cuma dapat fotokopi slipnya: dicoret di dapur pun, slip asli di kasir tetap bersih. Slip itu argumen, dapur itu fungsinya, nampannya return value.

🧪 Tebakan cepat: fungsi naikkan(m Menu) mengisi m.Harga = 18000. Sesudah naikkan(bakso), baris fmt.Println(bakso.Harga) di main mencetak 15000 atau 18000? Tebak dulu, jawabannya ada di bagian "Argumen selalu disalin".

Bentuk sebuah fungsi

package main

import "fmt"

func subtotal(harga int, porsi int) int {
	return harga * porsi
}

func cetakStruk(nama string, jumlah int) {
	fmt.Println(nama, jumlah)
}

func main() {
	bayar := subtotal(15000, 3)
	cetakStruk("Bakso urat", bayar)
	fmt.Println(subtotal(12000, 2))
}
$ go run bakso.go
Bakso urat 45000
24000

Argumen selalu disalin

Go selalu memberi fungsi salinan argumennya. Struct Menu disalin seluruhnya:

type Menu struct {
	Nama  string
	Harga int
}

func naikkan(m Menu) {
	m.Harga = 18000
	fmt.Println("di naikkan:", m.Harga)
}

func main() {
	bakso := Menu{Nama: "Bakso urat", Harga: 15000}
	naikkan(bakso)
	fmt.Println("di main:", bakso.Harga)
}
di naikkan: 18000
di main: 15000

m adalah fotokopi bakso. Yang berubah cuma fotokopinya, dan fotokopi itu dibuang begitu naikkan selesai. Jadi main tetap mencetak 15000. Itu jawaban tebakannya.

Supaya fungsi bisa mengubah yang asli, kirim alamatnya:

func naikkan(m *Menu) {
	m.Harga = 18000
}

naikkan(&bakso) // sekarang di main: 18000

Variadic: jumlah argumen bebas

... sebelum tipe parameter terakhir artinya "boleh berapa pun":

func total(harga ...int) int {
	jumlah := 0
	for _, h := range harga {
		jumlah += h
	}
	return jumlah
}

pesanan := []int{15000, 12000, 5000}
fmt.Println(total(15000, 12000, 5000)) // 32000
fmt.Println(total(pesanan...))         // 32000
fmt.Println(total())                   // 0

Fungsi juga nilai: closure

Fungsi bisa disimpan di variabel dan dikembalikan dari fungsi lain. Fungsi yang memakai variabel di luar dirinya disebut closure, dan ia membawa variabel itu ke mana pun:

func penghitung() func() int {
	nomor := 0
	return func() int {
		nomor++
		return nomor
	}
}

ambil := penghitung()
fmt.Println("ambil:", ambil()) // ambil: 1
fmt.Println("ambil:", ambil()) // ambil: 2
lain := penghitung()
fmt.Println("lain:", lain())   // lain: 1

Hasil yang diberi nama

Hasil fungsi boleh diberi nama di signature. Variabelnya langsung ada sejak awal fungsi, berisi zero value, dan return tanpa apa-apa (bare return) mengembalikannya:

func subtotal(harga, porsi int) (hasil int) {
	if porsi <= 0 {
		return // hasil masih 0
	}
	hasil = harga * porsi
	return
}

fmt.Println(subtotal(15000, 0), subtotal(15000, 3)) // 0 45000

Di fungsi pendek, return hasil yang ditulis jelas lebih gampang dibaca.

⚠️ Jebakan yang sering ketemu

TL;DR: Fungsi ditulis func nama(parameter tipe) tipeHasil { return ... }, dan parameter bertipe sama boleh disingkat: func tambah(a, b int) int. Argumen masuk sesuai urutan dan selalu disalin, jadi naikkan(m Menu) gak mengubah bakso; kirim &bakso ke parameter *Menu untuk mengubah yang asli. ...int menerima berapa pun argumen sebagai slice, dan slice dikirim dengan total(pesanan...). Fungsi adalah nilai: closure membawa variabelnya sendiri, jadi ambil() mengembalikan 1, 2, 3. Hasil boleh diberi nama, lalu return kosong (bare return) mengembalikannya. Lupa return berarti missing return.

Yang akan kamu pelajari