2026'da Go Generics: Tip Parametreleri, Kısıtlamalar ve Mülakat Soruları

Go generics konusunda kapsamlı mülakat hazırlık rehberi. Tip parametreleri, kısıtlamalar, tilde operatörü ve pratik kod örnekleri.

2026'da Go Generics: Tip Parametreleri, Kısıtlamalar ve Mülakat Soruları

Go 1.18, Mart 2022'de dile generics özelliğini kazandırdı ve o zamandan beri bu özellik Go 1.21, 1.22 ve sonraki sürümlerle olgunlaştı. Bu makale, temel tip parametrelerinden işe alım yöneticilerinin sıkça sorduğu gelişmiş kısıtlama kalıplarına kadar 2026 için temel Go generics mülakat sorularını ele almaktadır.

Go Generics Nedir?

Go generics, derleme zamanı tip güvenliğini koruyarak herhangi bir veri tipiyle çalışan fonksiyonlar ve tipler yazmayı sağlar. Çalışma zamanı tip dönüşümleri kullanan arayüzlerin aksine, generics tipleri derleme zamanında çözerek daha iyi performans ve daha erken hata tespiti sağlar.

Go'da Tip Parametrelerini Anlamak

Tip parametreleri Go generics'in temelini oluşturur. Bir tip parametresi, generic fonksiyon veya tip kullanıldığında belirlenen bir tip için yer tutucudur.

generic.gogo
// Basic generic function with type parameter T
func PrintSlice[T any](items []T) {
    for _, item := range items {
        fmt.Println(item)
    }
}

// Usage - type inference determines T automatically
func main() {
    PrintSlice([]int{1, 2, 3})        // T is int
    PrintSlice([]string{"a", "b"})     // T is string
}

Köşeli parantez sözdizimi [T any], any ile kısıtlanmış bir T tip parametresi bildirir. Go derleyicisi somut tipi argümanlardan çıkarır ve çoğu durumda açık tip belirtme ihtiyacını ortadan kaldırır.

Yaygın Mülakat Sorusu: any ve comparable Arasındaki Fark Nedir?

Mülakatçılar sıklıkla yerleşik kısıtlamalar olan any ve comparable hakkında soru sorar. Aralarındaki farkları anlamak, sağlam generics bilgisini gösterir.

constraints.gogo
// any: accepts all types (alias for interface{})
func Process[T any](value T) T {
    return value
}

// comparable: only types that support == and !=
func Contains[T comparable](slice []T, target T) bool {
    for _, v := range slice {
        if v == target {  // This comparison requires comparable
            return true
        }
    }
    return false
}

// This compiles
Contains([]int{1, 2, 3}, 2)

// This fails: slices are not comparable
// Contains([][]int{{1}, {2}}, []int{1})

comparable kısıtlaması, tip parametrelerini eşitlik operatörlerini destekleyen tiplerle sınırlar. Dilimler, haritalar ve fonksiyonlar hariç tutulur çünkü Go dil seviyesinde bunlar için eşitlik tanımlamaz.

Arayüzlerle Özel Tip Kısıtlamaları Oluşturma

Go, generic fonksiyonların kabul edebileceğini genişleten özel kısıtlamaları tanımlamak için arayüzleri kullanır. Go spesifikasyonu tip elemanlarının kısıtlama arayüzlerinde nasıl çalıştığını tanımlar.

number.gogo
// Custom constraint using type union
type Number interface {
    int | int8 | int16 | int32 | int64 |
    uint | uint8 | uint16 | uint32 | uint64 |
    float32 | float64
}

// Generic function constrained to numeric types
func Sum[T Number](values []T) T {
    var total T
    for _, v := range values {
        total += v  // + operator works because all Number types support it
    }
    return total
}

func main() {
    fmt.Println(Sum([]int{1, 2, 3}))         // 6
    fmt.Println(Sum([]float64{1.5, 2.5}))    // 4.0
}

| ile tip birlikleri, kısıtlamayı hangi tiplerin karşıladığını belirler. Bu yaklaşım, çalışma zamanı tip dönüşümlerinden kaçınırken any'den daha fazla kontrol sağlar.

Mülakat Sorusu: Kısıtlamalarda ~ Tilde Operatörünü Açıklayın

Kısıtlamalardaki tilde operatörü ~, hem bir tipi hem de o tipi temel tip olarak alan tüm tipleri eşleştirir. Bu soru Go'nun tip sisteminin anlaşılmasını test eder.

underlying.gogo
// ~int matches int and any type with int as underlying type
type Signed interface {
    ~int | ~int8 | ~int16 | ~int32 | ~int64
}

// Custom type with int as underlying type
type UserID int
type Temperature int64

func Abs[T Signed](value T) T {
    if value < 0 {
        return -value
    }
    return value
}

func main() {
    var id UserID = -42
    var temp Temperature = -10
    
    fmt.Println(Abs(id))    // 42 - works because ~int matches UserID
    fmt.Println(Abs(temp))  // 10 - works because ~int64 matches Temperature
}

~ olmadan, int kısıtlaması yalnızca tam int tipini eşleştirir, UserID gibi özel tipleri değil. Tilde, kısıtlamayı türetilmiş tipleri içerecek şekilde genişleterek generic kodu daha esnek hale getirir.

Go mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Generic Tipler: Struct'lar ve Metodlar

Generic tipler fonksiyonların ötesine geçerek struct'ları ve metodları kapsar. Bu kalıp veri yapısı implementasyonlarında sıkça görülür.

stack.gogo
// Generic Stack type
type Stack[T any] struct {
    items []T
}

// Push adds an element to the stack
func (s *Stack[T]) Push(item T) {
    s.items = append(s.items, item)
}

// Pop removes and returns the top element
func (s *Stack[T]) Pop() (T, bool) {
    if len(s.items) == 0 {
        var zero T  // Zero value for type T
        return zero, false
    }
    index := len(s.items) - 1
    item := s.items[index]
    s.items = s.items[:index]
    return item, true
}

func main() {
    intStack := Stack[int]{}
    intStack.Push(10)
    intStack.Push(20)
    
    val, ok := intStack.Pop()  // val=20, ok=true
}

Generic tiplerdeki metodların tip parametresini parantez içinde tekrarlaması gerekir, ancak yeni tip parametreleri tanıtamaz. Alıcı (s *Stack[T]), metodu belirli Stack örneklemesine bağlar.

Mülakat Sorusu: Metodlar Neden Kendi Tip Parametrelerine Sahip Olamaz?

Go metodlarda ek tip parametrelerini yasaklar, bu Java veya C# gibi dillerden gelen geliştiricileri şaşırtan bir tasarım kararıdır. Go generics önerisi bu sınırlamanın tip sistemini yönetilebilir tutmak için var olduğunu açıklar.

go
// This is NOT valid Go code
type Container[T any] struct {
    value T
}

// ERROR: methods cannot have type parameters
// func (c *Container[T]) Transform[U any](fn func(T) U) U {
//     return fn(c.value)
// }

// Valid alternative: use a standalone function
func Transform[T, U any](c *Container[T], fn func(T) U) U {
    return fn(c.value)
}

Çözüm, metodlar yerine birden fazla tip parametresine sahip üst düzey fonksiyonlar kullanmaktır. Bu tasarım metod dağıtımını basit tutar ve alıcı tipleri ile metod tip parametreleri arasındaki karmaşık etkileşimleri önler.

Tip Çıkarımı ve Kısıtlama Çıkarımı

Go'nun tip çıkarımı, generic fonksiyonları çağırırken ayrıntılılığı azaltır. Açık tip argümanlarının ne zaman gerekli olduğunu anlamak, daha temiz kod yazmaya yardımcı olur.

inference.gogo
func Map[T, R any](input []T, transform func(T) R) []R {
    result := make([]R, len(input))
    for i, v := range input {
        result[i] = transform(v)
    }
    return result
}

func main() {
    numbers := []int{1, 2, 3}
    
    // Type inference: T=int, R=string inferred from arguments
    strings := Map(numbers, func(n int) string {
        return fmt.Sprintf("%d", n)
    })
    
    // Explicit types sometimes required for complex cases
    // Map[int, string](numbers, converter)
}

Tip çıkarımı fonksiyon argümanlarından tip parametrelerine doğru çalışır. Derleyici tipleri yalnızca argümanlardan çıkaramadığında, köşeli parantez içindeki açık tip argümanları belirsizliği çözer.

Constraints Paketi: Standart Kütüphanede cmp ve slices

Go 1.21, Ordered kısıtlaması ve karşılaştırma fonksiyonlarıyla cmp paketini ekledi. slices paketi, standart kütüphanede deyimsel generic kodu gösterir.

stdlib.gogo
import (
    "cmp"
    "slices"
)

func main() {
    numbers := []int{3, 1, 4, 1, 5, 9}
    
    // slices.Sort uses cmp.Ordered constraint internally
    slices.Sort(numbers)  // [1, 1, 3, 4, 5, 9]
    
    // Binary search on sorted slice
    index, found := slices.BinarySearch(numbers, 4)
    
    // cmp.Compare returns -1, 0, or 1
    result := cmp.Compare(3, 5)  // -1
    
    // cmp.Or returns first non-zero value
    value := cmp.Or(0, 0, 42, 100)  // 42
}

Standart kütüphane dokümantasyonu, bu paketlerin sıralı tipler üzerinde tip güvenli işlemler için generics'i nasıl kullandığını gösterir. Bu paketlere aşinalık, teorik anlayışın ötesinde pratik generics bilgisini gösterir.

Mülakat Sorusu: Generic Önbellek Implementasyonu

Yaygın bir mülakat alıştırması, adaylardan generic, thread-safe bir önbellek implementasyonu ister. Bu, generics, sync paketi ile eşzamanlılık ve API tasarımını test eder.

cache.gogo
import (
    "sync"
    "time"
)

type Cache[K comparable, V any] struct {
    mu    sync.RWMutex
    items map[K]cacheItem[V]
}

type cacheItem[V any] struct {
    value      V
    expiration time.Time
}

func NewCache[K comparable, V any]() *Cache[K, V] {
    return &Cache[K, V]{
        items: make(map[K]cacheItem[V]),
    }
}

func (c *Cache[K, V]) Set(key K, value V, ttl time.Duration) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.items[key] = cacheItem[V]{
        value:      value,
        expiration: time.Now().Add(ttl),
    }
}

func (c *Cache[K, V]) Get(key K) (V, bool) {
    c.mu.RLock()
    defer c.mu.RUnlock()
    
    item, exists := c.items[key]
    if !exists || time.Now().After(item.expiration) {
        var zero V
        return zero, false
    }
    return item.value, true
}

Bu implementasyon, anahtarlar için comparable (harita gereksinimi) ve değerler için any kullanır. Ayrı cacheItem struct'ı, generic tiplerin birbirinin içine nasıl yerleştirilebileceğini gösterir. Thread güvenliği, Go eşzamanlılık mülakatlarında ele alınan bir kalıp olan sync.RWMutex'ten gelir.

Sıfır Değerler ve Tip Kısıtlamaları

Generic kodda sıfır değerlerini işlemek, Go'nun parametreli tiplerin değişkenlerini nasıl başlattığını anlamayı gerektirir.

zero.gogo
// Return zero value when slice is empty
func First[T any](slice []T) T {
    if len(slice) == 0 {
        var zero T  // Zero value: 0 for int, "" for string, nil for pointers
        return zero
    }
    return slice[0]
}

// Alternative: return pointer to avoid ambiguity
func FirstOrNil[T any](slice []T) *T {
    if len(slice) == 0 {
        return nil
    }
    return &slice[0]
}

var zero T kalıbı, herhangi bir T tipi için sıfır değeri oluşturur. Sıfırın geçerli bir değer olduğu tipler için (tamsayılar için 0 gibi), işaretçi döndüren varyant "bulunamadı" ile "sıfır bulundu" arasında ayrım yapar.

Gelişmiş: Birden Fazla Kısıtlamayı Birleştirme

Karmaşık generic fonksiyonlar, tiplerin birden fazla kısıtlamayı karşılamasını gerektirebilir. Go bunu arayüz gömme yoluyla işler.

combined.gogo
// Constraint requiring both ordering and string conversion
type Stringable interface {
    String() string
}

type OrderedStringable interface {
    cmp.Ordered
    Stringable
}

// Alternative: use type parameters with multiple constraints inline
func PrintSorted[T interface{ cmp.Ordered; fmt.Stringer }](items []T) {
    slices.Sort(items)
    for _, item := range items {
        fmt.Println(item.String())
    }
}

Arayüz gömme kısıtlamaları birleştirir ve tiplerin tüm gömülü arayüzleri uygulamasını gerektirir. Satır içi sözdizimi interface{ A; B }, adlandırılmış bir kısıtlama tipi bildirmeden aynı işlevselliği sağlar.

Sonuç

  • [T any] ile tip parametreleri, çalışma zamanı yansıması olmadan yeniden kullanılabilir, tip güvenli kod yazmayı sağlar
  • comparable, harita anahtarları için gerekli olan == ve != destekleyen tiplerle sınırlar
  • Tilde ~, belirli bir temel tipe sahip tipleri eşleştirir ve kısıtlama esnekliğini genişletir
  • Özel kısıtlamalar, izin verilen tipleri belirtmek için tip birliklerini (int | string) kullanır
  • Metodlar kendi tip parametrelerine sahip olamaz; alternatif olarak üst düzey fonksiyonlar kullanılır
  • Standart kütüphane paketleri cmp ve slices deyimsel generic kalıpları gösterir
  • var zero T ile sıfır değerler, generic fonksiyonlarda boş veya eksik verileri işler
  • Thread-safe generic veri yapıları, generics'i senkronizasyon primitive'leriyle birleştirir

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Etiketler

#go
#generics
#interview

Paylaş

İlgili makaleler