Topik ini membahas deklarasi konstanta dengan kata kunci const, perbedaan konstanta bertipe dan tak bertipe, serta pola enum bernomor otomatis dengan pengenal iota. Konstanta menyimpan nilai yang ditetapkan pada saat kompilasi dan tidak dapat diubah selama program berjalan, sehingga tepat untuk nilai tetap yang bermakna, misalnya satuan konversi dan nama status. Setelah membaca topik ini, nilai tetap dapat dinyatakan dengan bentuk yang paling sesuai dan deret konstanta dapat disusun tanpa menomori satu per satu.
Deklarasi konstanta#
Konstanta dideklarasikan dengan const nama = nilai atau const nama tipe = nilai, baik di tingkat package maupun di dalam fungsi. Nilainya wajib dapat dihitung saat kompilasi, sehingga bilangan, string, nilai logika, dan ekspresi yang menyusun ketiganya sah, sedangkan hasil pemanggilan fungsi pada waktu berjalan tidak. Program berikut memakai konstanta di tingkat package maupun lokal, lalu mencetak seluruhnya:
package main
import "fmt"
type hari int
const (
senin hari = iota
selasa
rabu
)
const (
_ = iota // lewati nilai 0
kiB = 1 << (10 * iota) // 1 << 10
miB = 1 << (10 * iota) // 1 << 20
giB = 1 << (10 * iota) // 1 << 30
)
func main() {
fmt.Println("senin bernilai", int(senin))
fmt.Println("selasa bernilai", int(selasa))
fmt.Println("rabu bernilai", int(rabu))
fmt.Println("Satu kiB =", kiB, "byte")
fmt.Println("Satu miB =", miB, "byte")
fmt.Println("Satu giB =", giB, "byte")
const detikPerJam = 3600
fmt.Println("Satu jam =", detikPerJam, "detik")
}senin bernilai 0
selasa bernilai 1
rabu bernilai 2
Satu kiB = 1024 byte
Satu miB = 1048576 byte
Satu giB = 1073741824 byte
Satu jam = 3600 detikUpaya memberi nilai baru pada konstanta menghasilkan error kompilasi dengan pesan cannot assign to ..., karena konstanta bukan lokasi memori yang dapat ditulis. Sifat tidak berubah itulah yang membedakannya dari variabel, dan itulah alasan konstanta dipilih untuk nilai yang tidak boleh tergeser secara tidak sengaja di tengah program.
Deklarasi konstanta sebaiknya dikelompokkan dalam satu blok berkurung ketika semuanya sejenis, karena blok menjadi tempat alami untuk menyusun nilai yang saling terkait sebagaimana tampak pada program di atas. Konstanta tingkat package dapat dipakai oleh seluruh berkas dalam package yang sama, sehingga menjadi titik tunggal untuk nilai yang dirujuk lintas berkas. Penamaannya mengikuti aturan yang sama dengan variabel, yaitu huruf kapital pada awal nama membuat konstanta terlihat oleh package lain.
Konstanta bertipe dan tak bertipe#
Konstanta di Go terbagi dua bentuk. Konstanta bertipe menyebut tipenya secara eksplisit, misalnya const batas int = 1000, sehingga berperilaku seperti nilai int yang tidak berubah. Konstanta tak bertipe tidak menyebut tipe apa pun, misalnya const detikPerJam = 3600, dan justru bentuk inilah yang lebih fleksibel. Konstanta tak bertipe menyimpan nilainya dengan presisi berapa pun yang diperlukan pada saat kompilasi, lalu menyesuaikan diri dengan konteks pemakaiannya.
Fleksibilitas itu paling terlihat pada batas ukuran. Konstanta tak bertipe 1 << 40 sah dan dapat diisi ke variabel int64, karena penyesuaian tipenya terjadi per pemakaian. Memasukkan konstanta yang sama ke int32 ditolak kompilator karena nilainya tidak muat. Kedua deklarasi pada potongan berikut memakai konstanta yang sama, tetapi hanya satu yang lolos kompilasi.
// tidak-dijalankan
const besar = 1 << 40 // konstanta tak bertipe, tanpa batas tipe
var p64 int64 = besar // sah, nilai 1099511627776 muat di int64
var p32 int32 = besar // error kompilasi: overflow int32Perbandingan meter < detikPerJam pun sah tanpa konversi, padahal meter bertipe int, karena konstanta tak bertipe sementara mengambil tipe yang cocok dengan operan di sebelahnya. Kemudahan ini menjelaskan mengapa banyak konstanta pustaka standar dinyatakan tanpa tipe, misalnya math.Pi, sehingga dapat dipakai bersama float32 maupun float64 tanpa salinan baru.
Apabila sebuah konstanta tak bertipe dipakai di tempat yang menuntut satu tipe tertentu tanpa petunjuk lain, ia mengambil tipe bawaannya. Tipe bawaan bilangan bulat adalah int dan tipe bawaan pecahan adalah float64, sedangkan konstanta teks mengambil tipe string. Pengetahuan ini menjelaskan perilaku konstanta yang dipakai tanpa konteks tipe, sekaligus menjadi alasan konstanta tak bertipe dianggap lebih fleksibel, karena tipe bawaan hanya dipakai sebagai pilihan terakhir.
Pola enum dengan iota#
iota adalah pengenal yang bernilai indeks baris di dalam satu blok const, dimulai dari nol, dan naik satu untuk setiap baris konstanta berikutnya. Baris yang hanya menuliskan nama tanpa ekspresi mengulang ekspresi baris sebelumnya, sehingga deret nilai berurutan dapat dibuat ringkas. Pola ini menjadi padanan enum yang ada pada bahasa lain. Tipe baru seperti type hari int disandingkan dengan blok const, agar nilai-nilainya memiliki tipe sendiri dan tidak tertukar dengan bilangan biasa.
Blok kedua pada program di atas memperlihatkan dua tambahan yang sering muncul. Baris pertama berisi _ = iota, yaitu konstanta dengan pengenal kosong _ yang menyimpan nilai 0 tanpa memberinya nama, sehingga nama yang sesungguhnya dimulai dari 1. Ekspresi 1 << (10 * iota) kemudian menggeser bit sesuai posisi baris, menghasilkan 1024, 1048576, dan 1073741824 untuk satu kiB, satu miB, dan satu giB. Penulisan demikian menyatakan hubungan antar nilai secara langsung, sehingga menambah satu ukuran baru cukup menambah satu baris.
Memilih antara const dan var#
Aturan pemilihannya sederhana, yaitu gunakan const apabila nilai memang dirancang tetap dan var apabila nilainya berubah. Konstanta menghapus satu sumber bug klasik, yaitu nilai yang tergeser oleh penugasan yang tidak disengaja, sekaligus mendokumentasikan maksud. Nilai yang dinyatakan sebagai variabel lalu berubah tanpa sengaja menyisakan gejala yang sulit dilacak, sedangkan konstanta memindahkan pemeriksaannya ke saat kompilasi dengan pesan yang menunjuk baris penugasan itu secara langsung.
Deretan nilai kategori yang berpotensi menjadi kompleks sebaiknya disusun sebagai tipe baru dengan iota sejak awal, agar pergantian perilaku berdasarkan kategori dapat ditangani rapi oleh switch pada topik alur kontrol. Untuk nilai yang hanya relevan di dalam satu fungsi, konstanta lokal pun cukup, tanpa perlu mengeksposnya ke tingkat package.
Ringkasan#
constmenetapkan nilai pada saat kompilasi, dan penugasan ulang terhadapnya adalah error kompilasi.- Konstanta tak bertipe menyimpan nilai dengan presisi berapa pun dan menyesuaikan tipe per pemakaian, sedangkan konstanta bertipe berperilaku seperti nilai tipe itu.
iotabernilai indeks baris pada blokconst, dan baris tanpa ekspresi mengulang ekspresi baris sebelumnya.- Pola enum Go memadukan tipe baru, blok
const, daniota, dengan_sebagai cara melompati nilai awal.
Referensi#
- The Go Blog: Constants — The Go Blog — Penjelasan resmi konstanta tak bertipe, presisi arbitrer, dan cara konstanta menyesuaikan konteks.
- A Tour of Go: Constants — Go Documentation — Latihan resmi deklarasi konstanta dan konstanta numerik.
- The Go Programming Language Specification — The Go Project
— Spesifikasi resmi konstanta, konstanta
iota, dan aturan representasinya.