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 fieldZero value
int, int64, dan bilangan bulat lain0
float640.0
boolfalse
stringstring kosong ""
slice []Tnil
map[K]Vnil
pointer, chan, funcnil
array [N]Tsetiap elemen berisi zero value T
structsetiap 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:

go
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:

bash
go run zero-demo.go

Output yang Dihasilkan:

text
{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{}{}: true

Mari kita telaah baris demi baris program di atas:

  1. Baris 5–12 (type Pengukur struct ...): mendeklarasikan struct dengan field bertipe string, bool, float64, int, slice, dan map — perwakilan hampir semua kelompok zero value.
  2. Baris 20–21 (var p Pengukur): mendeklarasikan p tanpa nilai awal; %+v membuktikan seluruh field terisi zero value secara otomatis, termasuk Tanda:[] untuk slice nil dan Label:map[] untuk map nil.
  3. Baris 23–25 (fmt.Println tiga baris): membandingkan tiap field langsung dengan zero value-nya — hasil true menegaskan nilai awal yang pasti, bukan sekadar tampilan cetakan.
  4. Baris 27–29 (a dan b): membuat dua struct Status berisi field sejenis; operator == membandingkan field per field sehingga a == b bernilai true.
  5. Baris 31–32 (b.Aktif = false): mengubah field pada b saja. Nilai a tidak ikut berubah karena assignment struct menyalin seluruh isi struct.
  6. Baris 34–35 (var kosong struct{}): mendeklarasikan struct kosong; cetakannya {} dan nilainya selalu sama dengan struct{}{}.

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:

go
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)
}
bash
go run error-comparable.go

Output yang Dihasilkan:

text
# 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 #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

error-comparable.go

Unduh berkas
go
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)
}

zero-demo.go

Unduh berkas
go
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{}{})
}