Deklarasi var p Pengukur tidak mengisi satu field pun, tetapi program tetap berjalan tanpa nilai sampah. Go menjamin setiap variabel yang belum diisi memperoleh zero value — nilai awal yang pasti untuk setiap tipe. Jaminan ini berdampak besar pada desain struct: tipe yang dirancang agar zero value-nya langsung berguna tidak memerlukan inisialisasi khusus sebelum dipakai. Pada chapter ini kita bedah zero value setiap tipe, perbandingan struct dengan ==, struct yang tidak bisa dibandingkan karena berisi slice, serta struct kosong struct{}.
Zero Value Setiap Tipe #
Zero value bukan memori acak, melainkan konstanta pasti yang ditentukan oleh tipe. Tabel berikut merangkum zero value untuk tipe yang paling sering dipakai sebagai field:
| Tipe field | Zero value |
|---|---|
int, int64, dan bilangan bulat lain | 0 |
float64 | 0.0 |
bool | false |
string | string kosong "" |
slice []T | nil |
map[K]V | nil |
pointer, chan, func | nil |
array [N]T | setiap elemen berisi zero value T |
| struct | setiap field berisi zero value-nya |
Perhatikan pola pembagian tiga kelompok: bilangan menjadi nol, bool menjadi false, string menjadi kosong, sedangkan tipe referensi (slice, map, pointer) menjadi nil. Untuk struct, zero value diterapkan berlapis sampai field paling dalam.
Zero Value Struct Otomatis #
Struct Pengukur di bawah sengaja memuat enam field dengan tipe berbeda agar zero value tiap tipe terlihat sekali jalan:
package main
import "fmt"
type Pengukur struct {
Nama string
Aktif bool
Suhu float64
JumlahData int
Tanda []string
Label map[string]string
}
type Status struct {
Nama string
Aktif bool
}
func main() {
var p Pengukur
fmt.Printf("%+v\n", p)
fmt.Println(p.Nama == "", p.Aktif == false)
fmt.Println(p.Suhu == 0.0, p.JumlahData == 0)
fmt.Println(p.Tanda == nil, p.Label == nil)
a := Status{Nama: "Termometer", Aktif: true}
b := Status{Nama: "Termometer", Aktif: true}
fmt.Println("a == b:", a == b)
b.Aktif = false
fmt.Println("a == b setelah b diubah:", a == b)
var kosong struct{}
fmt.Println("kosong:", kosong, "sama dengan struct{}{}:", kosong == struct{}{})
}Jalankan program dari direktori chapter:
go run zero-demo.goOutput yang Dihasilkan:
{Nama: Aktif:false Suhu:0 JumlahData:0 Tanda:[] Label:map[]}
true true
true true
true true
a == b: true
a == b setelah b diubah: false
kosong: {} sama dengan struct{}{}: trueMari kita telaah baris demi baris program di atas:
- Baris 5–12 (
type Pengukur struct ...): mendeklarasikan struct dengan field bertipestring,bool,float64,int, slice, dan map — perwakilan hampir semua kelompok zero value. - Baris 20–21 (
var p Pengukur): mendeklarasikanptanpa nilai awal;%+vmembuktikan seluruh field terisi zero value secara otomatis, termasukTanda:[]untuk slicenildanLabel:map[]untuk mapnil. - Baris 23–25 (
fmt.Printlntiga baris): membandingkan tiap field langsung dengan zero value-nya — hasiltruemenegaskan nilai awal yang pasti, bukan sekadar tampilan cetakan. - Baris 27–29 (
adanb): membuat dua structStatusberisi field sejenis; operator==membandingkan field per field sehinggaa == bbernilaitrue. - Baris 31–32 (
b.Aktif = false): mengubah field padabsaja. Nilaiatidak ikut berubah karena assignment struct menyalin seluruh isi struct. - Baris 34–35 (
var kosong struct{}): mendeklarasikan struct kosong; cetakannya{}dan nilainya selalu sama denganstruct{}{}.
Membandingkan Struct dengan == #
Operator == pada struct membandingkan seluruh field secara berurutan dan hanya sah jika semua field bertipe comparable. Tipe bilangan, bool, string, pointer, array, dan struct lain yang comparable semuanya boleh dibandingkan. Perilaku ini melengkapi semantik salinan: dua struct bernilai sama jika isinya identik, dan mengubah satu salinan tidak memengaruhi salinan lain.
Field Slice Membuat Struct Non-Comparable #
Satu field slice saja sudah cukup membuat struct tidak bisa dibandingkan dengan ==. Berkas error-comparable.go berikut membuktikannya:
package main
import "fmt"
type DaftarBelanja struct {
Pemilik string
Barang []string
}
func main() {
a := DaftarBelanja{Pemilik: "Budi"}
b := DaftarBelanja{Pemilik: "Budi"}
fmt.Println(a == b)
}go run error-comparable.goOutput yang Dihasilkan:
# command-line-arguments
./error-comparable.go:13:14: invalid operation: a == b (struct containing []string cannot be compared)Program di atas sengaja gagal dikompilasi — pesan galat itulah materinya. Kompilator menolak perbandingan karena []string tidak punya definisi kesetaraan, sehingga DaftarBelanja yang memuatnya ikut non-comparable. Larangan yang sama berlaku untuk field bertipe map atau fungsi.
Struct Kosong struct #
Struct tanpa field, struct{}, menempati nol byte memori. Semua nilainya identik, seperti dibuktikan baris terakhir program utuh. Karena tidak memuat data dan tidak memakan tempat, struct{} dipakai sebagai penanda: channel chan struct{} menjadi sinyal “selesai” tanpa memuat muatan, dan map[string]struct{} menjadi himpunan kunci yang murah.
Zero Value Bukan null #
Nilai struct tidak pernah nil. Variabel var p Pengukur sudah berisi struct lengkap yang bisa langsung dibaca — bandingkan dengan bahasa yang mengisi objek baru dengan null dan menuntut constructor sebelum objek dipakai. Yang bisa nil hanyalah pointer ke struct (*Pengukur), seperti dibahas pada section Pointer dan Memory
. Kalaupun zero value tidak valid bagi domain tertentu, misalnya akun tanpa nama, validasi awal dikerjakan lewat constructor yang kita bahas pada chapter Constructor Pattern
.
Referensi #
- Spesifikasi Go: The zero value — definisi resmi zero value setiap tipe.
- Spesifikasi Go: Comparison operators — aturan tipe comparable.
- Dokumentasi package fmt
— cetakan zero value oleh
%+v.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
error-comparable.go
Unduh berkaspackage main
import "fmt"
type DaftarBelanja struct {
Pemilik string
Barang []string
}
func main() {
a := DaftarBelanja{Pemilik: "Budi"}
b := DaftarBelanja{Pemilik: "Budi"}
fmt.Println(a == b)
}
zero-demo.go
Unduh berkaspackage main
import "fmt"
type Pengukur struct {
Nama string
Aktif bool
Suhu float64
JumlahData int
Tanda []string
Label map[string]string
}
type Status struct {
Nama string
Aktif bool
}
func main() {
var p Pengukur
fmt.Printf("%+v\n", p)
fmt.Println(p.Nama == "", p.Aktif == false)
fmt.Println(p.Suhu == 0.0, p.JumlahData == 0)
fmt.Println(p.Tanda == nil, p.Label == nil)
a := Status{Nama: "Termometer", Aktif: true}
b := Status{Nama: "Termometer", Aktif: true}
fmt.Println("a == b:", a == b)
b.Aktif = false
fmt.Println("a == b setelah b diubah:", a == b)
var kosong struct{}
fmt.Println("kosong:", kosong, "sama dengan struct{}{}:", kosong == struct{}{})
}