Generics
Memahami generics di Go β type parameter, constraint, dan contoh penggunaan.
Versi Bahasa Indonesia. Baca dalam Bahasa Inggris
Generics di Go (diperkenalkan di Go 1.18) memungkinkan Anda mendefinisikan fungsi atau tipe yang dapat bekerja dengan tipe data apa pun sambil mempertahankan type-checking yang ketat. Ini menghilangkan kebutuhan akan kode boilerplate atau menggunakan tipe interface{} yang kurang aman pada saat kompilasi.
Konsep Utama
Type Parameters
func PrintSlice[T any](slice []T) {
for _, v := range slice {
fmt.Println(v)
}
}- Generics menggunakan type parameter dalam kurung siku
[]untuk menentukan tipe yang dapat diterima oleh suatu fungsi atau tipe. - Di sini, T adalah type parameter yang dapat mewakili tipe apa pun.
Constraints
func Add[T int | float64](a, b T) T {
return a + b
}- Constraint mendefinisikan operasi apa yang diizinkan pada type parameter.
- Di sini, T dibatasi hanya ke int atau float64, memastikan operator
+valid.
Constraint any
- Keyword
anyadalah alias untukinterface{}dan mewakili tipe apa pun tanpa batasan.
Manfaat
- Compile-Time Safety: Compiler Go menegakkan kebenaran tipe pada saat kompilasi. Mengurangi error runtime.
- Monomorphization: Untuk performa, compiler menghasilkan versi spesifik dari fungsi/tipe generik untuk setiap tipe yang digunakan. Ini menghindari overhead runtime.
- Code Reusability: Menghindari duplikasi fungsi atau struktur data yang serupa.
- Performa: Tidak seperti
interface{}, generics tidak memerlukan type assertion atau reflection.
Contoh
Generic Functions
Fungsi yang bekerja dengan tipe apa pun
package main
import "fmt"
func PrintSlice[T any](slice []T) {
for _, v := range slice {
fmt.Println(v)
}
}
func main() {
PrintSlice([]int{1, 2, 3})
PrintSlice([]string{"a", "b", "c"})
}Output:
1
2
3
a
b
cGeneric Types
Mendefinisikan struktur data dengan type parameter:
package main
import "fmt"
// Stack adalah generic stack
type Stack[T any] struct {
items []T
}
func (s *Stack[T]) Push(item T) {
s.items = append(s.items, item)
}
func (s *Stack[T]) Pop() T {
last := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
return last
}
func main() {
s1 := Stack[int]{}
s1.Push(10)
s1.Push(20)
fmt.Println(s1.Pop()) // 20
fmt.Println(s1.Pop()) // 10
s2 := Stack[string]{}
s2.Push("A")
s2.Push("B")
fmt.Println(s2.Pop()) // B
fmt.Println(s2.Pop()) // A
}Output:
20
10
B
A- Pada contoh di atas kita dapat membuat stack yang bekerja dengan tipe apa pun.
- Ini lebih aman daripada menggunakan
interface{}karena tipenya dipaksakan pada saat kompilasi, bukan di-casting manual saat runtime.
Multiple Type Parameters
Fungsi atau tipe dengan lebih dari satu type parameter:
package main
import "fmt"
func Combine[K comparable, V any](keys []K, values []V) map[K]V {
result := make(map[K]V)
for i, key := range keys {
result[key] = values[i]
}
return result
}
func main() {
keys := []string{"a", "b", "c"}
values := []int{1, 2, 3}
fmt.Println(Combine(keys, values))
// tukar posisinya
fmt.Println(Combine(values, keys))
}Output:
map[a:1 b:2 c:3]
map[1:a 2:b 3:c]- Pada contoh di atas kita membuat map generik yang dapat menerima tipe
anysebagai value-nya. - Perhatikan bahwa kita menggunakan
comparablealih-alihanykarenamapdi Go membutuhkan ini untuk menghindari ambiguitas, inefisiensi, dan potensi bug terkait tipe yang mutable atau tidak comparable.
New Constraints
Membatasi type parameter dengan constraint:
package main
import "fmt"
type Number interface {
int | int64 | float64
}
func Sum[T Number](a, b T) T {
return a + b
}
func main() {
fmt.Println(Sum(1, 1))
fmt.Println(Sum(1.1, 1.1))
}Output:
2
2.2-
Pada contoh di atas kita membatasi fungsi
Sumuntuk hanya menerima tipeNumberyang kita definisikan sebagaiint,int64, ataufloat64. -
Jika kita mencoba memasukkan string sebagai parameter
Sum("A", "B")maka akan mengembalikan error:string does not satisfy Number (string missing in int | int64 | float64)
Last updated on