Fungsi

Parameter, banyak nilai kembalian, dan hasil bernama.

Daftar isi

Fungsi adalah unit dasar penyusunan program Go, yaitu blok kode bernama yang menerima masukan dan menghasilkan keluaran. Topik ini membahas deklarasi fungsi, aturan parameternya, nilai kembalian tunggal dan banyak, serta hasil bernama. Setelah membaca topik ini, setiap deklarasi fungsi dapat ditulis dengan bentuk nilai kembalian yang tepat sesuai kebutuhan program.

Deklarasi fungsi dan parameternya#

Sebuah fungsi dideklarasikan dengan kata kunci func, diikuti nama, daftar parameter bertipe, dan tipe nilai kembalian. Nama fungsi di Go menggabungkan beberapa kata tanpa spasi dengan huruf kapital pada awal kata baru, misalnya fahrenheitKeCelsius. Tipe setiap parameter ditulis setelah nama parameternya, sedangkan tipe nilai kembalian ditulis setelah daftar parameter. Komentar di atas deklarasi menjadi dokumentasi fungsi yang tampil pada alat bantu baca kode.

go Bentuk umum deklarasi fungsi
// tidak-dijalankan
func namaFungsi(paramA int, paramB string) float64 {
	return 0.0
}

Dua parameter yang bertipe sama boleh ditulis berurutan dengan satu deklarasi tipe, seperti panjang, lebar float64. Parameter berperilaku sebagai salinan nilai yang dikirim pemanggil, sehingga perubahan terhadap parameter di dalam fungsi tidak memengaruhi variabel pemanggil. Untuk memengaruhi data pemanggil, fungsi perlu mengembalikan hasil perubahannya sebagai nilai kembalian, dan cara inilah yang menjadi konvensi umum di Go.

Go tidak menyediakan nilai bawaan parameter dan tidak mengenal overloading, yaitu beberapa fungsi bernama sama yang dibedakan oleh tanda tangannya. Satu nama fungsi hanya memiliki satu tanda tangan, sehingga variasi kebutuhan masukan dijawab dengan nama fungsi yang berbeda atau dengan bentuk parameter yang lebih fleksibel. Aturan ini menjaga setiap pemanggilan tetap tunggal makna karena satu nama tidak mungkin merujuk dua fungsi yang berbeda.

Urutan deklarasi dan lingkup#

Deklarasi fungsi pada tingkat paket dapat diletakkan dalam urutan apa pun di dalam berkas. Kompilator membaca seluruh berkas sebelum memeriksa pemanggilan, sehingga sebuah fungsi boleh memanggil fungsi lain yang deklarasinya berada di bawahnya. Susunan bebas ini sering dimanfaatkan untuk menempatkan func main di bagian atas berkas agar alur program utama terbaca lebih dahulu.

go Pemanggilan sebelum deklarasi
// tidak-dijalankan
func main() {
	fmt.Println(sisa(7, 4))
}

// sisa menghitung sisa pembagian a terhadap b.
func sisa(a, b int) int {
	return a % b
}

Lingkup nama pada fungsi mengikuti aturan yang sederhana. Parameter dan variabel yang dideklarasikan di dalam fungsi hanya hidup di dalam fungsi itu, sehingga nama yang sama bebas dipakai oleh fungsi lain tanpa saling menimpa. Sebaliknya, fungsi bernama tidak dapat dideklarasikan di dalam fungsi lain, dan kebutuhan semacam itu dijawab dengan fungsi tanpa nama, yaitu fungsi yang dibuat langsung di dalam ekspresi.

Nilai kembalian tunggal#

Bentuk fungsi yang paling umum mengembalikan satu nilai bertipe tertentu. Program berikut memuat dua fungsi konversi satuan yang masing-masing mengembalikan satu float64. Ekspresi di dalam badan fungsi dihitung dari parameternya tanpa keadaan di luar fungsi, sehingga hasilnya selalu sama untuk masukan yang sama.

go konversi-suhu.go
package main

import "fmt"

// fahrenheitKeCelsius mengonversi suhu dari derajat Fahrenheit ke Celsius.
func fahrenheitKeCelsius(f float64) float64 {
	return (f - 32) * 5 / 9
}

// kmPerJamKeMeterPerDetik mengonversi kecepatan dari km/jam ke m/detik.
func kmPerJamKeMeterPerDetik(k float64) float64 {
	return k * 1000 / 3600
}

func main() {
	fmt.Printf("68 F = %.2f C\n", fahrenheitKeCelsius(68))
	fmt.Printf("72 km/jam = %.2f m/detik\n", kmPerJamKeMeterPerDetik(72))
}
text Keluaran
68 F = 20.00 C
72 km/jam = 20.00 m/detik

Sifat hasil yang hanya bergantung pada masukan membuat fungsi mudah diuji dan mudah dibaca ulang. Pemanggilan fahrenheitKeCelsius(68) dapat ditempatkan langsung di dalam argumen fmt.Printf karena hasilnya satu nilai. Verb %.2f memformat bilangan pecahan dengan dua angka di belakang koma, sehingga keluarannya rapi dan tetap.

Banyak nilai kembalian#

Go mengembalikan lebih dari satu nilai dengan mendaftarkan tipe-tipe kembaliannya di dalam tanda kurung. Fitur ini menjadi fondasi pola terpenting di Go, yaitu fungsi yang mengembalikan nilai hasil bersama penanda keberhasilan atau error. Program berikut memuat satu fungsi dengan dua hasil sekaligus satu fungsi yang melaporkan keberhasilan pembagiannya.

go nilai-kembalian.go
package main

import "fmt"

// ukurKotak mengembalikan luas dan keliling persegi panjang sekaligus.
func ukurKotak(panjang, lebar float64) (float64, float64) {
	return panjang * lebar, 2 * (panjang + lebar)
}

// bagi membagi a dengan b dan melaporkan keberhasilan lewat nilai kedua.
func bagi(a, b int) (int, bool) {
	if b == 0 {
		return 0, false
	}
	return a / b, true
}

func main() {
	luas, keliling := ukurKotak(4, 3)
	fmt.Println("kotak 4x3: luas", luas, "keliling", keliling)

	hasil, ok := bagi(10, 2)
	fmt.Println("10 : 2 =", hasil, ok)

	hasil, ok = bagi(7, 0)
	fmt.Println("7 : 0 =", hasil, ok)
}
text Keluaran
kotak 4x3: luas 12 keliling 14
10 : 2 = 5 true
7 : 0 = 0 false

Fungsi ukurKotak mengembalikan dua float64 yang ditangkap dua variabel sekaligus melalui :=. Fungsi bagi mengembalikan (int, bool) untuk memisahkan hasil hitung dari status keberhasilannya. Apabila hanya sebagian hasil yang dibutuhkan, variabel yang tidak dipakai diganti tanda garis bawah, misalnya luas, _ := ukurKotak(4, 3).

Pemanggilan yang mengembalikan banyak nilai hanya dapat diletakkan sebagai satu-satunya argumen bagi fungsi lain. Begitu pemanggilan itu bercampur dengan argumen lain, hasilnya harus ditangkap ke variabel terlebih dahulu sebelum dipakai. Aturan kecil ini menjelaskan mengapa pola (nilai, error) hampir selalu ditangkap dengan nilai, err := ... sebelum diperiksa.

Hasil bernama#

Daftar nilai kembalian boleh diberi nama, dan nama tersebut menjadi variabel yang siap dipakai di dalam badan fungsi. Bentuk ini berfungsi sebagai dokumentasi tanda tangan, sebab makna setiap hasil terbaca tanpa harus membuka badan fungsinya. Program berikut menamai kedua hasilnya luas dan keliling.

go hasil-bernama.go
package main

import "fmt"

// dimensi menghitung luas dan keliling persegi panjang.
// Nama hasil berfungsi sebagai dokumentasi tanda tangan fungsi.
func dimensi(panjang, lebar float64) (luas, keliling float64) {
	luas = panjang * lebar
	keliling = 2 * (panjang + lebar)
	return
}

func main() {
	fmt.Println(dimensi(4, 3))
	fmt.Println(dimensi(10, 2.5))
}
text Keluaran
12 14
25 25

Pernyataan return tanpa operand, disebut return telanjang (naked return), mengembalikan nilai terkini dari setiap hasil bernama. Pada fungsi pendek seperti dimensi, bentuk ini jelas dan tidak menimbulkan salah baca. Pada fungsi yang badannya panjang, return telanjang justru menyembunyikan alur data sehingga nilai yang dikembalikan sulit ditelusuri.

go Return telanjang pada fungsi panjang
// tidak-dijalankan
func proses(data string) (bersih string, n int) {
	// puluhan baris logika di sini
	return // sulit ditelusuri nilai apa yang sedang dikembalikan
}

Hasil bernama juga berperilaku sebagai variabel biasa yang dapat dibaca kode lain di dalam fungsi. Fungsi yang ditunda dengan defer, misalnya, dapat membaca dan menyunting hasil bernama tersebut sebelum kendali benar-benar kembali kepada pemanggil. Kombinasi keduanya menjadi idiom tersendiri pada penanganan pembersihan sumber daya.

Kesalahan umum#

  • Menganggap parameter dikirim dengan referensi. Perubahan pada parameter di dalam fungsi tidak terlihat oleh pemanggil karena yang diterima fungsi adalah salinan nilai. Perbaikannya, kembalikan hasil perubahan sebagai nilai kembalian dan tetapkan ulang variabel pemanggil.
  • Menangkap sebagian dari banyak nilai kembalian. Pernyataan luas := ukurKotak(4, 3) gagal dikompilasi dengan pesan assignment mismatch karena jumlah nilainya tidak cocok. Perbaikannya, tangkap seluruh hasil atau gantikan yang tidak dipakai dengan tanda garis bawah.
  • Memakai return telanjang pada fungsi panjang. Nilai kembalian menjadi sulit dilacak karena setiap jalur keluar mengembalikan keadaan terkini yang tersebar di banyak baris. Perbaikannya, batasi return telanjang pada fungsi pendek dan tulis operand return secara eksplisit untuk fungsi yang lebih panjang.

Ringkasan#

  • Deklarasi fungsi menuliskan tipe setiap parameter dan tipe nilai kembaliannya secara eksplisit.
  • Parameter berperilaku sebagai salinan nilai dari pemanggil, dan satu nama fungsi hanya memiliki satu tanda tangan.
  • Banyak nilai kembalian ditulis dalam tanda kurung dan menjadi dasar pola (nilai, error).
  • Hasil bernama mendokumentasikan tanda tangan fungsi dan mendukung return telanjang pada fungsi pendek.

Referensi#