Go punya dua cara untuk mendeklarasikan variabel: var, yang bisa dipakai di mana saja, dan :=, bentuk singkat yang bisa dipakai di dalam fungsi dan menebak tipenya secara otomatis.
Setiap variabel punya tipe tetap yang ditentukan saat kompilasi. Saat kamu memberi nilai, Go menebak tipenya dari nilai itu, jadi menulis tipenya juga (var city string = "Lisbon") memang sah tetapi berlebihan.
var vs :=
var | := | |
|---|---|---|
| Tempat | level package dan di dalam fungsi | hanya di dalam fungsi |
| Tipe | opsional; wajib kalau tidak ada nilai | selalu ditebak otomatis |
| Nilai awal | opsional (selain itu zero value) | wajib |
| Deklarasi ulang | tidak pernah | boleh kalau minimal satu variabel di sisi kiri adalah variabel baru |
Pilihan yang idiomatis di dalam fungsi:
x := valuekalau kamu punya nilai awal.var x Tkalau kamu menginginkan zero value, yang menandakan "sengaja kosong":var buf bytes.Buffer,var total int.var x T = valuekalau tipe hasil tebakan bukan tipe yang kamu inginkan, misalnyavar ratio float64 = 1(ratio := 1biasa akan bertipeint).
:= di luar fungsi adalah syntax error:
./main.go:5:1: syntax error: non-declaration statement outside function body
Zero value
Variabel yang dideklarasikan tanpa nilai tidak pernah berisi sampah. Variabel itu berisi zero value dari tipenya:
| Tipe | Zero value |
|---|---|
| integer, float | 0 |
bool | false |
string | "" |
| pointer, slice, map, channel, fungsi, interface | nil |
| array, struct | setiap elemen atau field diisi zero value-nya |
API Go yang baik dirancang agar zero value-nya berguna: sync.Mutex yang bernilai nol dalam keadaan tidak terkunci, bytes.Buffer yang bernilai nol kosong dan siap dipakai, dan len, range, serta append semuanya bisa dipakai pada slice nil. Yang perlu diwaspadai adalah map: membaca map nil mengembalikan zero value, tetapi menulis ke map nil akan panic. Buat map dengan make atau literal sebelum menyimpan isinya.
Mendeklarasikan beberapa variabel
Blok var ( ... ) mengelompokkan variabel di level package yang saling terkait. Dalam assignment ganda seperti x, y = y, x, setiap ekspresi di sisi kanan dievaluasi sebelum ada yang di-assign, dan itulah sebabnya pertukaran nilai ini berhasil.
:= dengan beberapa nama tidak mendeklarasikan ulang apa pun selama minimal satu nama di sisi kiri adalah nama baru. Nama yang sudah ada di scope yang sama hanya diberi nilai baru. Inilah yang memungkinkan kamu memakai ulang err:
f, err := os.Open("a.txt") // declares f and err
g, err := os.Open("b.txt") // declares g, assigns to the existing err
Kalau tidak ada satu pun nama yang baru, hasilnya error:
./main.go:7:4: no new variables on left side of :=
Pakai = biasa untuk memberi nilai ke variabel yang sudah ada.
Variabel yang tidak dipakai adalah error
Variabel lokal yang dideklarasikan tetapi tidak pernah dibaca akan menghentikan build:
./main.go:9:2: declared and not used: x
Ini bukan peringatan yang bisa kamu matikan. Hapus variabelnya, pakai, atau, saat sedang debugging, bungkam dengan blank identifier: _ = x. Blank identifier juga membuang nilai kembalian yang tidak kamu butuhkan: _, err := fmt.Println("hi").
Variabel di level package dan parameter fungsi dikecualikan dari aturan ini.
Scope dan shadowing
Sebuah variabel ada sejak deklarasinya sampai akhir blok yang membungkusnya ({ ... }). := di dalam blok yang lebih dalam membuat variabel baru, walaupun ada variabel dengan nama yang sama di luar. Variabel di luar itu tertutupi (shadowed), bukan diubah:
Program ini mencetak inside: 42 lalu outside: 0. := di dalam if mendeklarasikan count dan err sebagai variabel baru di blok dalam, karena keduanya belum ada di sana. Kode ini bisa dikompilasi tanpa masalah dan menjadi sumber klasik bug "nilaiku hilang".
Cara memperbaikinya adalah mendeklarasikan err lebih dulu dan memberi nilai dengan =:
var err error
count, err = strconv.Atoi(input)
go vet tidak melaporkan shadowing secara default. Analyzer shadow yang terpisah bisa melakukannya, dan linter seperti golangci-lint bisa mengaktifkannya.
Penamaan
- Pakai
camelCase:maxRetries,userID. Bukanmax_retries. - Tulis akronim dalam satu jenis huruf:
userID,httpClient,parseURL, bukanuserId. - Nama pendek untuk scope yang pendek:
idi perulangan,runtuk reader,erruntuk error. Nama yang lebih panjang dan deskriptif untuk variabel di level package. - Nama yang diawali huruf besar di level package (
var Timeout) diekspor ke package lain. Lihat halaman package dan import.
Variabel di level package
Variabel yang dideklarasikan di luar fungsi hidup selama program berjalan dan diinisialisasi sebelum main dijalankan, sesuai urutan ketergantungannya. Variabel ini praktis untuk konfigurasi dan cache, dan dipakai bersama oleh semua goroutine. Kalau lebih dari satu goroutine menulis ke variabel seperti itu, lindungi dengan mutex atau pakai sync/atomic, karena kalau tidak, akan terjadi data race.
Pakai konstanta untuk nilai yang tidak pernah berubah. const tidak bisa diubah secara tidak sengaja dan tidak ada biayanya saat program berjalan.
Pertanyaan yang sering diajukan
Apa bedanya var dan := di Go?
:= mendeklarasikan dan menginisialisasi variabel dengan tipe yang ditebak otomatis, dan hanya bisa dipakai di dalam fungsi: count := 10. var bisa dipakai di mana saja (termasuk di level package), memungkinkan kamu menyebut tipenya, dan boleh tanpa nilai awal untuk mendapatkan zero value: var count int. Di dalam fungsi, Go yang idiomatis memakai := kalau ada nilai awal dan var kalau kamu menginginkan zero value.
Apa itu zero value di Go?
Setiap variabel yang dideklarasikan tanpa nilai mendapat zero value dari tipenya: 0 untuk angka, false untuk bool, "" untuk string, dan nil untuk pointer, slice, map, channel, fungsi, dan interface. Struct mendapat zero value untuk setiap field-nya. Go tidak punya variabel yang belum terinisialisasi.
Bagaimana cara memperbaiki error "declared and not used" di Go?
Go menolak variabel lokal yang diberi nilai tetapi tidak pernah dibaca. Pakai variabel itu, hapus, atau, saat sedang debugging, berikan ke blank identifier dengan _ = x. Variabel di level package dan parameter fungsi dikecualikan.
Bagaimana cara mendeklarasikan variabel global di Go?
Pakai var di level package, di luar fungsi mana pun: var counter int. Bentuk singkat := tidak diizinkan di sana. Nama yang diawali huruf besar (var Counter int) terlihat oleh package lain; nama yang diawali huruf kecil hanya terlihat di package-nya sendiri. Lindungi variabel di level package dengan mutex kalau ada goroutine yang menulis ke sana.