2026'da İleri Seviye Go Arayüzleri: Kompozisyon, Tip Doğrulamaları ve Mülakat Soruları

Go arayüz kompozisyonu, tip doğrulamaları ve Go 1.26 öz-referanslı jeneriklerde ustalaşın. Pratik örnekler ve teknik mülakat soruları içerir.

2026'da İleri Seviye Go Arayüzleri: Kompozisyon, Tip Doğrulamaları ve Mülakat Soruları

Go arayüzleri, implementasyon dayatmadan davranış tanımlar ve bu durum onları esnek, test edilebilir kod yazmanın merkezine yerleştirir. Go 1.26, öz-referanslı jenerikler, yeni reflection iteratörleri ve errors.AsType ile tip-güvenli hata işleme ekleyerek bu gücü genişletiyor. Bu rehber, arayüz kompozisyonunu, tip doğrulamalarını, gömme desenlerini ve teknik mülakatlarda karşılaşılan soruları kapsamaktadır.

Go 1.26 Arayüz Geliştirmesi

Jenerik tipler artık tip parametre listelerinde kendilerine referans verebiliyor: type Adder[A Adder[A]] interface { Add(A) A }. Bu F-sınırlı polimorfizm deseni, dönüş tiplerini implement eden tipe kısıtlayan arayüzler sağlar.

Arayüz Kompozisyonu ve Gömme Desenleri

Arayüz gömme, birden fazla arayüzü tek bir sözleşmede birleştirir. Sonuç, gömülü arayüzlerden tüm metotları gerektiren yeni bir arayüzdür. Bu desen, kod tekrarından kaçınır ve net soyutlama sınırları oluşturur.

interfaces.gogo
type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

type Closer interface {
    Close() error
}

// Composed interface embedding three interfaces
type ReadWriteCloser interface {
    Reader
    Writer
    Closer
}

Read, Write ve Close metotlarını implement eden herhangi bir tip, otomatik olarak ReadWriteCloser arayüzünü karşılar. Go standart kütüphanesi, io paketinde bu deseni yaygın olarak kullanır.

Yaygın bir mülakat sorusu, adaylardan Go'nun neden küçük, odaklı arayüzleri tercih ettiğini açıklamalarını ister. Cevap, kompozisyonda yatmaktadır: io.Reader yüzlerce fonksiyonda görünür çünkü tam olarak bir metot talep eder. Daha büyük arayüzler daha sıkı bağlantı oluşturur ve yeniden kullanımı azaltır.

Tip Doğrulamaları: Sözdizimi ve Güvenlik

Tip doğrulamaları, bir arayüz değerinden somut bir tipi çıkarır. İki değerli form, başarıyı gösteren bir boolean döndürerek paniklerden kaçınır.

assertions.gogo
func processValue(v interface{}) {
    // Two-value assertion: safe, no panic
    if str, ok := v.(string); ok {
        fmt.Printf("String value: %s\n", str)
        return
    }
    
    // Type switch for multiple types
    switch val := v.(type) {
    case int:
        fmt.Printf("Integer: %d\n", val)
    case float64:
        fmt.Printf("Float: %.2f\n", val)
    case []byte:
        fmt.Printf("Bytes: %x\n", val)
    default:
        fmt.Printf("Unknown type: %T\n", val)
    }
}

Tip switch'leri birden fazla olası tipi temiz bir şekilde işler. Her case, val değişkenini kendi bloğu içinde doğrulanan tipe bağlar ve ayrı doğrulamalara olan ihtiyacı ortadan kaldırır.

Panik Riski

str := v.(string) gibi tek değerli doğrulamalar, doğrulama başarısız olursa panik yapar. Üretim kodu her zaman iki değerli formu veya tip switch kullanmalıdır.

Mülakatçılar sıklıkla tip doğrulamalarının performansını sorar. Runtime, tip tanımlayıcılarının tek bir karşılaştırmasını gerçekleştirir ve bu doğrulamaları ucuz hale getirir. Maliyet, dolaylı referans nedeniyle büyük struct'lara işaretçileri saran arayüz değerlerinde artar, ancak doğrulamanın kendisi O(1) kalır.

Go 1.26'da Öz-Referanslı Jenerikler

Go 1.26, metotların implement eden tipi döndürmesi gereken arayüzleri mümkün kılan öz-referanslı tip parametrelerini tanıttı. Bazen F-sınırlı polimorfizm olarak adlandırılan bu desen, uzun süredir var olan bir sınırlamayı çözer.

builder.gogo
// Self-referential interface: methods return the same type
type Builder[B Builder[B]] interface {
    WithName(name string) B
    WithAge(age int) B
    Build() string
}

type PersonBuilder struct {
    name string
    age  int
}

func (p PersonBuilder) WithName(name string) PersonBuilder {
    p.name = name
    return p
}

func (p PersonBuilder) WithAge(age int) PersonBuilder {
    p.age = age
    return p
}

func (p PersonBuilder) Build() string {
    return fmt.Sprintf("%s, %d years old", p.name, p.age)
}

// Generic function using the self-referential constraint
func configure[B Builder[B]](b B, name string, age int) string {
    return b.WithName(name).WithAge(age).Build()
}

Builder[B] kısıtlaması, WithName ve WithAge metotlarının jenerik Builder yerine B döndürmesini sağlar. Bu olmadan, dönüş tipi arayüz olur, somut tip bilgisi kaybolur ve metot zincirleme bozulur.

Matematik tipleri bu desenden faydalanır. Bir Addable[A Addable[A]] arayüzü, Add(A) A metodunun aynı sayısal tipi döndürmesini sağlar ve BigInt ile Decimal değerlerinin yanlışlıkla karıştırılmasını önler.

errors.AsType: Tip-Güvenli Hata Açma

Go 1.26, errors.As içindeki işaretçi-dans desenini değiştiren errors.AsType özelliğini ekledi. Jenerik versiyon, açılmış hatayı doğrudan döndürür.

errors_handling.gogo
type ValidationError struct {
    Field   string
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("validation failed on %s: %s", e.Field, e.Message)
}

func handleError(err error) {
    // Go 1.26: generic type-safe unwrapping
    if valErr, ok := errors.AsType[*ValidationError](err); ok {
        log.Printf("Validation error on field %s\n", valErr.Field)
        return
    }
    
    // Before Go 1.26: pointer-based unwrapping
    // var valErr *ValidationError
    // if errors.As(err, &valErr) { ... }
    
    log.Printf("Unexpected error: %v\n", err)
}

Yeni API, ayrı değişken bildirimini ortadan kaldırır ve hedef tipi fonksiyon çağrısında açık hale getirir. Hata zincirleri öncekiyle aynı şekilde aranır; sadece arayüz değişti.

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

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

Arayüz İncelemesi için Reflection İteratörleri

Go 1.26, reflect paketine iteratör metotları ekledi. Type.Methods() ve Value.Methods(), metotlar üzerinde döngü için iteratörler döndürür ve indeks tabanlı döngülerin yerini alır.

reflection.gogo
import "reflect"

func inspectInterface(v interface{}) {
    t := reflect.TypeOf(v)
    
    // Go 1.26: iterator-based method inspection
    fmt.Printf("Type %s methods:\n", t.Name())
    for method := range t.Methods() {
        fmt.Printf("  %s: %s\n", method.Name, method.Type)
    }
    
    // For struct fields (also new in 1.26)
    if t.Kind() == reflect.Struct {
        for field := range t.Fields() {
            fmt.Printf("  Field: %s (%s)\n", field.Name, field.Type)
        }
    }
}

İteratör deseni, Go 1.23'ün range-over-function özelliğiyle uyumludur. Kod daha okunabilir hale gelir ve performans cezası yoktur: iteratörler değerleri tembel olarak üretir.

Derleme Zamanında Arayüz Uyumu

Go, somut bir değeri arayüz değişkenine atarken derleme zamanında arayüz uyumunu kontrol eder. Boş tanımlayıcı atamaları kullanarak yapılan açık kontroller, büyük kod tabanlarında hataları erken yakalar.

compile_check.gogo
type Storage interface {
    Save(key string, data []byte) error
    Load(key string) ([]byte, error)
    Delete(key string) error
}

type FileStorage struct {
    basePath string
}

// Compile-time check: fails if FileStorage misses a method
var _ Storage = (*FileStorage)(nil)

func (f *FileStorage) Save(key string, data []byte) error {
    path := filepath.Join(f.basePath, key)
    return os.WriteFile(path, data, 0644)
}

func (f *FileStorage) Load(key string) ([]byte, error) {
    path := filepath.Join(f.basePath, key)
    return os.ReadFile(path)
}

func (f *FileStorage) Delete(key string) error {
    return os.Remove(filepath.Join(f.basePath, key))
}

var _ Storage = (*FileStorage)(nil) satırı, yalnızca *FileStorage tipi Storage arayüzünü karşılıyorsa derlenir. Bu desen, eksik metotları bir değer atandığında çalışma zamanında değil, hemen yakalar.

Boş Arayüz ve Tip Kısıtlamaları

Boş arayüz interface{} herhangi bir değeri kabul eder ve any Go 1.18'den beri onun takma adıdır. Jenerik kısıtlamalar, çalışma zamanı doğrulamaları olmadan derleme zamanı tip güvenliği sağlar.

constraints.gogo
import "golang.org/x/exp/constraints"

// Generic function with numeric constraint
func Sum[T constraints.Integer | constraints.Float](values []T) T {
    var total T
    for _, v := range values {
        total += v
    }
    return total
}

// Comparable constraint for map keys
func Contains[K comparable, V any](m map[K]V, key K) bool {
    _, exists := m[key]
    return exists
}

interface{} yerine jenerikleri tercih etmek, tip doğrulamalarını ortadan kaldırır ve tip uyumsuzluklarını derleme zamanında yakalar. Dezavantaj, fonksiyon imzalarında artan karmaşıklıktır, bu nedenle jenerikler, bir fonksiyon gerçekten birden fazla tipte çalıştığında en uygun olanıdır.

Go Arayüzleri Üzerine Teknik Mülakat Soruları

Mülakatçılar, arayüz bilgisini birden fazla seviyede test eder. İşte kısa cevaplarla yaygın sorular.

S: Nil arayüz değerinde metot çağırdığınızda ne olur, arayüz içindeki nil somut değerle karşılaştırıldığında?

Nil arayüz, tip ve değere sahip değildir; herhangi bir metot çağrısı panik yapar. Nil işaretçi tutan nil olmayan bir arayüz bir tipe sahiptir; metot nil alıcıyla çalışır. Bu davranış, boş string döndüren (*bytes.Buffer)(nil).String() gibi desenlere olanak tanır.

S: Arayüz karşılaştırması nasıl çalışır?

İki arayüz değeri, aynı dinamik tipe ve eşit dinamik değerlere sahipse eşittir. Karşılaştırılamaz tiplerle (slice'lar, map'ler, fonksiyonlar) arayüzleri karşılaştırmak çalışma zamanında panik yapar.

S: Bir metot ne zaman değer alıcısı yerine işaretçi alıcısı kullanmalıdır?

İşaretçi alıcıları mutasyona izin verir ve büyük struct'ları kopyalamaktan kaçınır. Değer alıcıları eşzamanlı kullanım için güvenlidir ve hem değerlerle hem de işaretçilerle çalışır. Herhangi bir metot işaretçi alıcısına ihtiyaç duyuyorsa, o tipteki tüm metotlar tutarlılık için işaretçi alıcıları kullanmalıdır, çünkü yalnızca *T işaretçi-alıcı metodu gerektiren bir arayüzü karşılar.

receiver_rules.gogo
type Counter struct {
    count int
}

// Pointer receiver: modifies the struct
func (c *Counter) Increment() {
    c.count++
}

// Value receiver: read-only operation
func (c Counter) Value() int {
    return c.count
}

type Incrementer interface {
    Increment()
}

func main() {
    var c Counter
    // var i Incrementer = c  // Compile error: Counter lacks Increment
    var i Incrementer = &c     // OK: *Counter has Increment
    i.Increment()
}

S: "Arayüzleri kabul et, struct'ları döndür" ilkesini açıklayın.

Arayüzleri kabul eden fonksiyonlar, somut implementasyonlardan bağımsızlaşır ve mock'larla test etmeyi mümkün kılar. Somut tipler döndürmek, çağıranlara tip doğrulamaları olmadan tipin metotlarına tam erişim sağlar. Arayüz döndürmek, gelecekteki metot eklemelerini tip doğrulamasının arkasına gizler.

Daha fazla Go mülakat hazırlığı için Go eşzamanlılık soruları modülüne ve test modülüne bakılabilir.

Mülakat İpucu

Bir arayüz tasarlamanız istendiğinde, tek metotlu durumla başlayın. Yalnızca birden fazla metot her zaman birlikte çağrıldığında genişletin. Standart kütüphanenin Stringer, Reader ve Handler arayüzlerinin her biri tek bir metot tanımlar.

Kıdemli Go Geliştiricilerinin Arayüzler Hakkında Bilmesi Gerekenler

  • Gömme yoluyla arayüz kompozisyonu, kalıtım hiyerarşileri olmadan esnek sözleşmeler oluşturur. Arayüzleri küçük tutun: bir ila üç metot çoğu kullanım durumunu kapsar.
  • Tip doğrulamaları ve tip switch'leri somut tipleri güvenli bir şekilde çıkarır. Panikleri önlemek için üretim kodunda her zaman iki değerli formu veya switch kullanın.
  • Go 1.26'nın öz-referanslı jenerikleri, metotların implement eden tipi döndürmesi gereken builder desenleri ve matematik tiplerini mümkün kılar.
  • errors.AsType, jenerik, tip-güvenli bir API ile hata açmayı basitleştirir. Go 1.26 veya sonrasını hedefleyen yeni kodda kullanın.
  • var _ Interface = (*Type)(nil) ile derleme zamanı arayüz kontrolleri, testler çalışmadan önce eksik metotları yakalar.
  • Derleme zamanında tip güvenliği imza karmaşıklığından ağır bastığında interface{} yerine jenerikleri tercih edin.
  • "Arayüzleri kabul et, struct'ları döndür" yönergesi, tam işlevselliği açığa çıkarırken API'leri çağıranlar için esnek tutar.

Pratik yapmaya başla!

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

Günün meydan okuması

Go kodundaki hatayı bulabilir misin?

Gerçek bir kod parçası, gizli bir hata, günde bir deneme. Denemek için hesap gerekmez.

Anthony Fillion-Maillet

Yazan:

Anthony Fillion-Maillet

SharpSkill kurucusu

10 yılı aşkın süredir fullstack geliştirici. SharpSkill’i yönetiyor ve burada yayımlanan her şeyden sorumlu.

10 Eylül 2026 tarihinde güncellendi

Paylaş

İlgili makaleler