Struct Generik
Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan GO di Coddy. Pelajaran 70 dari 107.
Sama seperti fungsi, struct juga dapat memiliki parameter tipe. Struct generik memungkinkan kamu membuat struktur data yang berfungsi dengan tipe apa pun sambil tetap menjaga keamanan tipe. Ini cocok untuk membangun container yang dapat digunakan kembali, seperti stack, queue, atau pasangan kunci-nilai.
Untuk mendefinisikan struct generik, letakkan parameter tipe setelah nama struct:
type Box[T any] struct {
Value T
}
func main() {
intBox := Box[int]{Value: 42}
strBox := Box[string]{Value: "hello"}
fmt.Println(intBox.Value) // 42
fmt.Println(strBox.Value) // hello
}Tidak seperti fungsi generik, kamu harus menentukan tipe secara eksplisit saat membuat instance struct generik. Go tidak dapat menyimpulkan tipe hanya dari konteks.
struct generik dapat memiliki beberapa parameter tipe, sehingga ideal untuk struktur seperti pasangan atau map:
type Pair[K, V any] struct {
Key K
Value V
}
p := Pair[string, int]{Key: "age", Value: 25}
fmt.Printf("%s: %d\n", p.Key, p.Value) // age: 25Kamu juga bisa menerapkan batasan untuk memastikan tipe yang disimpan mendukung operasi tertentu:
type NumberBox[T int | float64] struct {
Value T
}
nb := NumberBox[float64]{Value: 3.14}struct generik menjadi dasar untuk membangun struktur data yang aman terhadap tipe dan dapat digunakan kembali di Go. Di pelajaran berikutnya, kamu akan belajar cara mendefinisikan method pada tipe generik ini.
Tantangan
MudahMari bangun sistem inventaris generik yang dapat melacak berbagai jenis item! Kamu akan membuat struktur container yang dapat digunakan kembali dan berfungsi dengan tipe apa pun, sambil tetap menjaga keamanan tipe sepenuhnya.
Kamu akan menyusun kodemu dalam dua file:
inventory.go: Definisikan struktur container generikmu.Buat struct generik
Item[T any]dengan dua field:Name(string) danData(bertipe T). Struct ini merepresentasikan item apa pun dengan data terkait yang tipenya fleksibel.Buat struct generik
Container[T any]dengan satu fieldItemsyang menampung sliceItem[T]. Container ini dapat menyimpan beberapa item dengan tipe data yang sama.Buat struct generik dengan batasan
PricedItem[T int | float64]dengan tiga field:Name(string),Quantity(int), danPrice(bertipe T). Batasan ini memastikan harga selalu berupa angka.Buat fungsi
NewContainer[T any]() *Container[T]yang membuat dan mengembalikan pointer ke Container kosong.Buat method
Addpada*Container[T]yang menerima nama (string) dan data (T), membuat Item, lalu menambahkannya ke slice Items milik container.Buat method
CountpadaContainer[T]yang mengembalikan jumlah item di dalam container.main.go: Tunjukkan penggunaan struktur generikmu dengan berbagai tipe.Baca tipe item (
string,int, ataupriced), lalu baca jumlah item, kemudian detail item.Untuk tipe
string: Baca pasangan nama dan data string. BuatContainer[string], tambahkan semua item, lalu cetak setiap item dengan format[Name]: [Data], diikuti jumlah total.Untuk tipe
int: Baca pasangan nama dan data bilangan bulat. BuatContainer[int], tambahkan semua item, lalu cetak setiap item dengan format[Name]: [Data], diikuti jumlah total.Untuk tipe
priced: Baca tiga nilai berupa nama, kuantitas, dan harga (sebagai float). Buat instancePricedItem[float64]secara langsung dan cetak setiap item dengan format[Name] x[Quantity] @ [Price], dengan harga ditampilkan hingga satu angka desimal.Cetak baris jumlah dengan format:
Total items: [count]
Input berikut akan diberikan:
- Baris 1: Tipe item (
string,int, ataupriced) - Baris 2: Jumlah item (bilangan bulat)
- Baris berikutnya: Detail item sesuai tipenya
Contohnya, jika diberikan:
string
3
Book
Fiction Novel
Pen
Blue Ink
Notebook
Lined PaperOutputmu seharusnya:
Book: Fiction Novel
Pen: Blue Ink
Notebook: Lined Paper
Total items: 3Dan jika diberikan:
int
2
Apples
50
Oranges
30Outputmu seharusnya:
Apples: 50
Oranges: 30
Total items: 2Dan jika diberikan:
priced
2
Widget
10
19.99
Gadget
5
49.50Outputmu seharusnya:
Widget x10 @ 19.9
Gadget x5 @ 49.5
Total items: 2Perhatikan bahwa struktur Container yang sama dapat digunakan dengan lancar untuk string maupun bilangan bulat, sedangkan PricedItem menggunakan batasan untuk memastikan hanya tipe numerik yang dapat digunakan untuk harga. Kamu harus menentukan parameter tipe secara eksplisit saat membuat instance struct generik ini.
Coba sendiri
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Baca tipe item
scanner.Scan()
itemType := scanner.Text()
// Baca count
scanner.Scan()
count, _ := strconv.Atoi(scanner.Text())
switch itemType {
case "string":
// TODO: Buat Container[string] menggunakan NewContainer
// TODO: Baca 'count' item (masing-masing memiliki nama pada satu baris dan data pada baris berikutnya)
// TODO: Tambahkan setiap item ke container
// TODO: Cetak setiap item dengan format "[Name]: [Data]"
// TODO: Cetak "Total items: [count]" menggunakan method Count
case "int":
// TODO: Buat Container[int] menggunakan NewContainer
// TODO: Baca 'count' item (masing-masing memiliki nama pada satu baris dan data bilangan bulat pada baris berikutnya)
// TODO: Tambahkan setiap item ke container
// TODO: Cetak setiap item dengan format "[Name]: [Data]"
// TODO: Cetak "Total items: [count]" menggunakan method Count
case "priced":
// TODO: Buat slice untuk menampung instance PricedItem[float64]
// TODO: Baca 'count' item (masing-masing memiliki nama, jumlah, dan harga pada baris terpisah)
// TODO: Buat PricedItem[float64] untuk setiap item dan tambahkan ke slice
// TODO: Cetak setiap item dalam format "[Name] x[Quantity] @ [Price]" dengan harga ditampilkan satu angka desimal
// TODO: Cetak "Total items: [count]"
}
_ = scanner // Gunakan scanner untuk membaca input
_ = count // Gunakan count untuk perulangan
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Objek
1Dasar-Dasar OOP di Go
File EksternalWorkspace Go dan modulePaket dan ImporNama yang Diekspor dan Tidak DieksporPengantar OOP di Gostruct sebagai classMendefinisikan method pada structPointer receiver vs value receiverInisialisasi structFungsi KonstruktorUlasan: Kalkulator Sederhana4Interface
Pengenalan InterfaceImplementasi ImplisitInterface sebagai KontrakInterface Kosong (any)Type AssertionType SwitchKomposisi InterfaceInterface Stringer & ErrorUlasan: Kalkulator Bentuk7Enkapsulasi
Field yang Diekspor vs Tidak DieksporEnkapsulasi Tingkat PackageMethod Getter dan SetterPenyembunyian Informasi di GoRingkasan: Data Siswa10Generics (Go 1.18+)
Pengantar GenericsParameter TipeBatasan TipeStruct GenerikCara Alternatif untuk Method GenerikRingkasan Koleksi Generik2Mendalami Tipe dan Struct
Tipe Dasar dan KompositDefinisi Tipe KustomTag StructStruct AnonimStruct BersarangNilai Nol dan Nilai BawaanRangkuman: Buku Kontak5Komposisi daripada Pewarisan
Mengapa Go Tidak Memiliki PewarisanDasar Penyematan StructPromosi methodMenyematkan Beberapa StructPenyematan vs AgregasiMembayangi method yang DisematkanRangkuman: Hierarki Karyawan8Penanganan Error & OOP
Interface errorTipe Error KustomPembungkusan Error (fmt.Errorf)Error Sentinelerrors.Is() dan errors.As()Panic, Defer, dan RecoverRangkuman: Parser File3Pointer dan Memori
Dasar-Dasar Pointer di GoPointer ke StructPass by Value vs ReferenceFungsi new()Garbage Collection di GoRekap: Pembuat Linked List6Polimorfisme di Go
Polimorfisme melalui InterfaceDuck Typing di GoAturan Pemenuhan InterfaceKoleksi PolimorfikInjeksi DependensiRangkuman: Pemroses Pembayaran9Konkruensi & OOP
Dasar-dasar GoroutineChannel & KomunikasiChannel Ber-buffer vs Tanpa BufferPernyataan selectsync.Mutex & sync.RWMutexsync.WaitGroupDesain Struct yang Aman untuk ThreadRingkasan: Worker PoolLatihan sendiri: Compiler Go online