Ana içeriğe geç
Modül 10 · Ders 3 ders 5Kurstaki 48/50~15 min
Modül dersleri (3/5)

Jenerikler (1.18+ sürümüne geçin)

Go 1.18'den (Mart 2022) bu yana tür parametreleri mevcuttur: işlevler ve türler, türler üzerinden parametrelendirilebilir. Kodu çoğaltmadan ve interface{} + çalışma zamanı türü iddiaları olmadan Map, Filter, Set[T], LinkedList[T] yazmanıza izin verirler.

Genel işlev: sözdizimi

Go
func Map[T, U any](s []T, f func(T) U) []U {
    out := make([]U, len(s))
    for i, v := range s {
        out[i] = f(v)
    }
    return out
}

doubled := Map([]int{1, 2, 3}, func(n int) int { return n * 2 })
// doubled is []int{2, 4, 6}

Üç yeni unsur:

  • [T, U any] addan sonra: tür parametrelerini kısıtlamalarıyla birlikte bildirir.
  • any = herhangi bir türü kabul eden kısıtlama (Go 1.18'den bu yana interface{} takma adı).
  • Çıkarım: Map([]int{...}, ...)'yi çağırdığınızda Map[int, int](...) yazmanıza gerek yoktur: derleyici T=int, U=int sonucunu çıkarır.

Bazen çıkarım yeterli olmaz (örneğin, T bağımsız değişkeni olmayan yapıcılar) ve açık örneklemeye ihtiyaç duyulur: New[*Server]().

Yerleşik kısıtlamalar

KısıtlamaAnlamı
anyHerhangi bir tür (== interface{}).
comparable== ve != içeren türler: sayısal, dize, bool, işaretçiler, kanallar, karşılaştırılabilir diziler/yapılar.

comparable eşitliğe izin verir ancak değil < veya >.

Go
func Index[T comparable](s []T, x T) int {
    for i, v := range s {
        if v == x { return i }
    }
    return -1
}

</> için özel bir kısıtlamaya ihtiyacınız vardır.

Özel kısıtlama: tür birleşimleri

Kısıtlama, "type element" cümleciklerini içeren bir arayüz'dür:

Go
type Ordered interface {
    ~int | ~int64 | ~float64 | ~string
}

func Min[T Ordered](a, b T) T {
    if a < b { return a }
    return b
}
  • | = birleşim: listelenen türlerden herhangi birini kabul eder.
  • ~int = "int veya type X int olarak tanımlanan herhangi bir tür" (aynı temel türle). ~ olmadan yalnızca tam int.

Bir kısıtlama ayrıca yöntemleri ve tür öğelerini karıştırabilir:

Go
type Stringable interface {
    ~string
    Len() int
}

Genel türler

Yalnızca işlevler değil, yapılar ve arayüzler de tür parametrelerine sahip olabilir.

Go
type Set[T comparable] struct {
    m map[T]struct{}
}

func NewSet[T comparable]() *Set[T] {
    return &Set[T]{m: make(map[T]struct{})}
}

func (s *Set[T]) Add(v T) { s.m[v] = struct{}{} }
func (s *Set[T]) Has(v T) bool { _, ok := s.m[v]; return ok }

s := NewSet[string]()
s.Add("ada")

Yöntemler türün dışındaki tür parametreleri EKLEYEMEZ: func (s *Set[T]) MapTo[U any](...) derlemez (kasıtlı tasarım sınırlaması).

Jenerikler ne zaman kullanılmalı?

Evet ne zaman:

  • Mantık, çeşitli türler için gerçekten aynıdır (koleksiyonlar, algoritmalar, Map/Filter/Reduce gibi yardımcılar).
  • Bunun alternatifi, kodu çoğaltmak veya interface{} + tür iddialarını kullanmak (tür güvenliğini kaybetmek) olabilir.

Hayır şu durumlarda:

  • Bir veya iki metoda sahip bir arayüz yeterlidir ve daha okunaklıdır (io.Reader, fmt.Stringer).
  • "Çünkü yapabilirsin" parametresini belirliyorsunuz: tek kullanımlık bir durum → bunun somut bir versiyonunu yapın.

Egzersizler

Egzersiz#go.m10.l3.e1
Denemeler: 0Yükleniyor…

Genel işlevi tanımlayın Min[T Ordered](a, b T) Operatör <'yi kullanarak küçük işlemi gerçekleştirin. Kısıtlama Düzenlendi ve çok güzel.

Düzenleyici yükleniyor…

3 denemeden sonra çözüm mevcut

Egzersiz#go.m10.l3.e2
Denemeler: 0Yükleniyor…

Harita[T, U herhangi](s []T, f func(T) U) []U: bir öğenin uygulanması ve yeni dilimin yeniden oluşturulması.

Düzenleyici yükleniyor…

3 denemeden sonra çözüm mevcut

Quiz#go.m10.l3.e3
Hazır

Nitelik kısıtlaması yerleşik operatör onayı == ma NON operatör <?

Go
func Index[T ???](s []T, x T) int { ... }
Cevap seçenekleri