Genel hikayeler veya generics, Go 1.18 sürümünden itibaren ortaya çıkmıştır. Uzun bir süre Go, basitlik uğruna genel hikayeleri dışlayan muhafazakar bir dil olarak kabul edilmiştir, ancak proje sayısının artması ve ekosisteminin gelişmesi, evrensel fonksiyonlar ve yapılar yazma ihtiyacını doğurmuştur. Bu, özellikle konteyner yapıları, koleksiyon işleme algoritmaları ve altyapı kodları için kritik bir önem taşımaktadır.
Sorun: Genel hikayelerden önce, kodu çoğaltmak veya boş arayüzler (interface{}) kullanmak zorundaydık, bu da tip güvenliğinin kaybına, performans düşüklüğüne ve hata ayıklamanın zorlaşmasına yol açıyordu.
Çözüm: Genel hikayeler, Go'da fonksiyonlar ve türler için köşeli parantezler içinde belirtilen tür parametreleri aracılığıyla uygulanmaktadır. Kısıtlamalar (constraints) ile geçerli tür parametrelerini sınırlamak mümkündür. Bu, tip güvenliği kaybedilmeden genel fonksiyonlar yazmayı sağlar.
Kod örneği:
package main import "fmt" type Adder[T any] func(a, b T) T func Sum[T any](slice []T, add Adder[T]) T { var result T for _, v := range slice { result = add(result, v) } return result } func intAdder(a, b int) int { return a + b } func main() { nums := []int{1, 2, 3, 4} sum := Sum(nums, intAdder) fmt.Println(sum) }
Anahtar özellikler:
Genel hikayelerdeki T tür parametreleri için herhangi bir aritmetik işlem (+, -, *, /) kullanılabilir mi?
Hayır. Go derleyicisi, tür parametresinin aritmetiği destekleyip desteklemediğini bilmez. Bunun için, Go 1.18+ ile kısıtlama, örneğin, işleci kısıtlamaları içeren bir arayüz belirtmek gerekir.
Kod örneği:
type Addable interface { int | float64 | uint } func Sum[T Addable](slice []T) T { var result T for _, v := range slice { result += v } return result }
Generic konteynerler, farklı türler için farklı davranışlarla yöntemler içerebilir mi?
Hayır. Genel türlerin veya fonksiyonların yöntemleri, tür değişimi kullanılmadığı sürece tüm türler için aynıdır. Davranış, kısıtlamalar aracılığıyla tanımlanmalı ya da tamamen parametreize edilmelidir.
Paket düzeyinde tür parametreleri (generic types) oluşturmak mümkün mü, yoksa yalnızca fonksiyonlar için mi?
Evet, Go 1.18'den itibaren hem genel fonksiyonlar hem de genel yapı türleri oluşturmak mümkündür:
type Stack[T any] struct { items []T } func (s *Stack[T]) Push(v T) { s.items = append(s.items, v) }
Koleksiyonlarla çalışmak için bir kütüphanede, interface{} aracılığıyla evrensel bir Map işlevselliği uygulandı:
Artılar:
Eksiler:
Aynı projede generics'e geçildi ve arayüzler aracılığıyla kısıtlamalar belirlendi:
Artılar:
Eksiler: