Generics (Go 1.18'de eklendi) tip parametreleri aracılığıyla birden fazla tip ile çalışan fonksiyonlar ve tipler yazmanıza olanak sağlarken, derleme zamanı tip güvenliğini korur. Bunlar, her tip için kod tekrarı yapmanın ya da interface{} ile güvenliği kaybetmenin eski ödününü ortadan kaldırır.
Generics'in çözdüğü sorun
// ❌ before generics — either duplicate per type...
func MaxInt(a, b int) int { ... }
func MaxFloat(a, b float64) float64 { ... } // copy-paste for each type
// ...or use interface{} and lose type safety + need casts/assertions
func Max(a, b interface{}) interface{} { ... } // unsafe, clunky
Genel bir fonksiyon
// T is a type parameter constrained to be "ordered" (comparable with < >)
func Max[T constraints.Ordered](a, b T) T {
if a > b {
return a
}
return b
}
Max(3, 5) // T inferred as int → 5
Max(2.5, 1.1) // T inferred as float64 → 2.5
Max("a", "b") // T inferred as string → "b"
[T constraints.Ordered] bir tip parametresi T bildirir ve constraint (hangi tiplere izin verildiği) tanımlar. Derleyici T'yi argümanlardan çıkarsar — bir uygulamada birçok tip için çalışır, tam tipe güvenlidir.
Tip constraint'leri
// a constraint is an interface listing allowed types or required methods
type Number interface {
~int | ~int64 | ~float64 // the | union means "any of these"
}
func Sum[T Number](nums []T) T {
var total T
for _, n := range nums {
total += n // safe — T is constrained to numeric types
}
return total
}
Sum([]int{1, 2, 3}) // 6
Sum([]float64{1.5, 2.5}) // 4.0
// built-in constraints:
any // any type (alias for interface{})
comparable // types usable with == (for map keys, etc.)
// golang.org/x/exp/constraints: Ordered, Integer, Float, etc.
Constraint'ler tip parametresi üzerinde hangi işlemlerin geçerli olduğunu tanımlar (~ "temel tipi bu olan herhangi bir tip" anlamına gelir).
Genel tipler
// a generic stack that works for any type
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 {
item := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
return item
}
intStack := Stack[int]{} // a stack of ints
strStack := Stack[string]{} // a stack of strings — same code
Ne zaman kullanılır (ve kullanılmaz)
✓ Generic data structures (stacks, trees, sets), utility functions over collections
(Map, Filter, Reduce), type-safe containers
✗ Don't overuse — if interfaces or a concrete type work simply, prefer them.
Go's philosophy still favors simplicity; generics are a tool, not a default.
Neden önemli
Generics, Go'ya yapılan büyük ve uzun süredir beklenen bir ekleme (1.18) olup, gerçek bir acı noktasını çözmüştür: bunlardan önce, birden fazla tip için yeniden kullanılabilir kod yazmak, ya her tip için kodu tekrarlamanıza (ayrıntılı, bakımı zor) ya da interface{} kullanmanıza (derleme zamanı tip güvenliğini kaybetme ve çalışma zamanı assert'ine ihtiyaç duyma) zorlamıştır.
Generics, tip güvenli ve yeniden kullanılabilir fonksiyonlar ve veri yapıları (container'lar, Map/Filter/Reduce gibi collection yardımcıları) yazmanıza, derleyicinin doğruluğu zorunlu kılması ve tipleri çıkarması ile olanak sağlar.
Tip parametrelerini, constraint'leri (any, comparable ve union/~ sözdizimi dahil) ve genel tipleri anlamak, ekosistem bunları benimserken giderek daha önemli hale gelmektedir.
Eşit derecede önemli olan, generics'lerin gerçek yeniden kullanım için bir araç, varsayılan değil olduğu Go zihniyetidir — aşırı kullanımı Go'nun sadelik felsefesine aykırı çalışır.
Bu, modern Go ile akıcılığı yansıtan güncel, sık tartışılan bir konudur.
