Struct — Go

Struct di Go Struct adalah cara Go mengelompokkan data terkait bersama-sama. Mirip dengan class di bahasa lain, tapi tanpa inheritance. Mendefinisikan Struct…

Struct mengelompokkan beberapa nilai yang saling terkait jadi satu, masing-masing dengan nama dan tipenya sendiri. Bayangin kartu menu di Warung Bakso Mas Bimo. Tiap kartu punya kolom yang sama: nama, harga, dan pedas atau gak. Struct adalah cetakan kartunya, dan tiap menu adalah satu kartu yang sudah diisi. Mirip object di JavaScript, bedanya kolom-kolomnya ditentukan dulu lewat sebuah tipe, dan gak bisa ditambah sembarangan.

🧪 Tebakan cepat: salinan := bakso, lalu salinan.Harga = 18000. Berapa bakso.Harga sekarang: 15000 atau 18000? Tebak dulu, jawabannya ada di bagian "Struct itu value: disalin utuh".

Mendefinisikan struct

type Menu struct {
	Nama  string
	Harga int
	Pedas bool
}

Bikin nilai struct

bakso := Menu{Nama: "Bakso urat", Harga: 15000, Pedas: true}
es := Menu{Nama: "Es teh", Harga: 5000}
var kosong Menu

fmt.Println(bakso)  // {Bakso urat 15000 true}
fmt.Println(es)     // {Es teh 5000 false}
fmt.Println(kosong) // { 0 false}

Baca, ubah, dan cetak field

fmt.Println(bakso.Nama, bakso.Harga) // Bakso urat 15000

fmt.Printf("%v\n", bakso)  // {Bakso urat 15000 true}
fmt.Printf("%+v\n", bakso) // {Nama:Bakso urat Harga:15000 Pedas:true}
fmt.Printf("%#v\n", bakso) // main.Menu{Nama:"Bakso urat", Harga:15000, Pedas:true}

bakso.Harga = 16000
fmt.Println(bakso.Harga) // 16000

Struct itu value: disalin utuh

bakso := Menu{Nama: "Bakso urat", Harga: 15000, Pedas: true}
salinan := bakso
salinan.Harga = 18000
fmt.Println(bakso.Harga, salinan.Harga) // 15000 18000

salinan := bakso menyalin semua field ke struct baru, sama seperti array dan beda dengan slice. Jadi bakso.Harga tetap 15000. Itu jawaban tebakannya.

Struct sebagai parameter function

func cetakMenu(m Menu) {
	fmt.Printf("\"%s\": Rp%d\n", m.Nama, m.Harga)
}

func naikkanHarga(m Menu) {
	m.Harga = 20000 // cuma mengubah salinan milik function ini
}
cetakMenu(bakso)         // "Bakso urat": Rp15000
cetakMenu(es)            // "Es teh": Rp5000
naikkanHarga(bakso)
fmt.Println(bakso.Harga) // 15000

Struct di dalam struct, dan anonymous struct

type Pesanan struct {
	Menu  Menu
	Porsi int
}

ps := Pesanan{Menu: es, Porsi: 2}
fmt.Printf("%+v\n", ps)                           // {Menu:{Nama:Es teh Harga:5000 Pedas:false} Porsi:2}
fmt.Println(ps.Menu.Nama, ps.Porsi*ps.Menu.Harga) // Es teh 10000

tamu := struct {
	Nama string
	Meja int
}{Nama: "Sari", Meja: 3}
fmt.Printf("%+v\n", tamu) // {Nama:Sari Meja:3}

💡 Field tag untuk JSON

type MenuJSON struct {
	Nama  string `json:"nama"`
	Harga int    `json:"harga"`
	Pedas bool   `json:"pedas,omitempty"`
	stok  int
}

b, _ := json.Marshal(MenuJSON{Nama: "Es teh", Harga: 5000, stok: 20})
fmt.Println(string(b)) // {"nama":"Es teh","harga":5000}

⚠️ Jebakan yang sering ketemu

TL;DR: type Menu struct { Nama string; Harga int } membuat tipe dengan field bernama. Nilainya dibuat dengan struct literal Menu{Nama: "Bakso urat", Harga: 15000}, field yang gak disebut berisi zero value, dan var m Menu semuanya zero value. m.Nama membaca dan mengubah field. %v mencetak nilainya, %+v dengan nama field, %#v seperti kode Go. Struct adalah value: assign dan parameter function membuat salinan. Anonymous struct adalah struct tanpa nama tipe, dan tag seperti json:"nama" dibaca package lain.

Yang akan kamu pelajari