Generics
Menulis function dan tipe yang bekerja untuk banyak tipe dengan type parameter.
Masalah tanpa generics
Tanpa generics, mencari nilai terbesar untuk int, float64, dan string butuh tiga function hampir kembar. Generics (sejak Go 1.18) menyelesaikannya dengan type parameter.
Function generik
func Maks[T int | float64 | string](a, b T) T {
if a > b {
return a
}
return b
}
fmt.Println(Maks(3, 9)) // 9 (T = int)
fmt.Println(Maks(2.5, 1.5)) // 2.5 (T = float64)
fmt.Println(Maks("apel", "jeruk")) // jeruk (T = string)
[T ...] mendeklarasikan type parameter. Setelahnya T dipakai seperti tipe biasa. Go menyimpulkan T dari argumen, jadi kamu tidak perlu menulis Maks[int](3, 9).
Constraint
Bagian setelah T adalah constraint: tipe apa saja yang diizinkan. Di atas dipakai gabungan int | float64 | string. Beberapa constraint bawaan:
any— semua tipe.comparable— tipe yang bisa dibandingkan dengan==(cocok untuk key map).- Paket
cmp:cmp.Ordered— semua tipe yang bisa diurutkan dengan<>.
Constraint juga bisa berupa interface buatan sendiri:
type Angka interface {
~int | ~int64 | ~float64
}
func Jumlah[T Angka](daftar []T) T {
var total T
for _, n := range daftar {
total += n
}
return total
}
Tipe generik
type Tumpukan[T any] struct {
data []T
}
func (t *Tumpukan[T]) Push(v T) { t.data = append(t.data, v) }
func (t *Tumpukan[T]) Pop() (T, bool) {
var kosong T
if len(t.data) == 0 {
return kosong, false
}
v := t.data[len(t.data)-1]
t.data = t.data[:len(t.data)-1]
return v, true
}
s := Tumpukan[int]{}
s.Push(1)
Kapan memakai generics?
Gunakan untuk struktur data dan fungsi utilitas yang logikanya identik untuk banyak tipe (Map, Filter, Reduce, Set, Stack). Untuk perilaku yang berbeda per tipe, interface biasanya lebih tepat. Jangan terlalu cepat memakai generics — mulailah dari kode konkret.