Menu
Coddy logo textTech

Generics'e Giriş

Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 67 / 107.

Go 1.18'den önce, farklı türler için yeniden kullanılabilir kod yazmak, ya fonksiyonları çoğaltmak ya da tür onaylamaları (type assertions) ile boş arayüz any kullanmak anlamına geliyordu. Generic'ler, tam tür güvenliğini korurken birden fazla türle çalışan fonksiyonlar ve türler yazmanıza olanak tanıyarak bu sorunu çözer.

Bir slice içindeki minimum değeri bulmayı düşünün. Generic yapılar olmadan, her tür için ayrı fonksiyonlara ihtiyacınız olurdu:

func MinInt(values []int) int {
    min := values[0]
    for _, v := range values {
        if v < min {
            min = v
        }
    }
    return min
}

func MinFloat64(values []float64) float64 {
    min := values[0]
    for _, v := range values {
        if v < min {
            min = v
        }
    }
    return min
}

Generic'ler ile, mantığı köşeli parantezler içindeki bir tip parametresi kullanarak bir kez yazarsınız:

func Min[T int | float64](values []T) T {
    min := values[0]
    for _, v := range values {
        if v < min {
            min = v
        }
    }
    return min
}

[T int | float64], hem int hem de float64 olabilen bir T tip parametresi tanımlar. Artık aynı fonksiyonla Min([]int{3, 1, 2}) veya Min([]float64{3.5, 1.2}) çağrısı yapabilirsiniz. Derleyici, tipleri derleme zamanında kontrol eder, böylece çalışma zamanı yükü olmadan güvenlik elde edersiniz.

Gelecek derslerde tür parametrelerini, kısıtlamaları ve generic struct'ları ayrıntılı olarak inceleyeceğiz.

challenge icon

Görev

Kolay

Generic yapıları kullanarak hem tam sayı hem de ondalıklı sayı puanlarıyla çalışan bir puan analizörü oluşturalım! Farklı sayısal türler için yinelenen kod ihtiyacını ortadan kaldırarak, bir dilimdeki (slice) maksimum değeri bulabilen tek bir generic fonksiyon oluşturacaksınız.

Kodunuzu iki dosya halinde düzenleyeceksiniz:

  • analyzer.go: Generic analiz fonksiyonunuzu tanımlayın.

    Bir dilimdeki maksimum değeri bulan ve döndüren generic bir Max[T int | float64](values []T) T fonksiyonu oluşturun. Fonksiyon, T tür parametresi aracılığıyla hem int hem de float64 türleriyle çalışmalıdır.

    Ayrıca bir dilimdeki tüm değerlerin toplamını hesaplayan ve döndüren generic bir Sum[T int | float64](values []T) T fonksiyonu oluşturun.

  • main.go: Girdiyi okuyun ve generic fonksiyonlarınızı farklı türlerle test edin.

    Bir tür göstergesi (int veya float) okuyun, ardından bir adet sayısı ve ardından o kadar değer okuyun. Değerleri türe göre ayrıştırın, uygun türle hem Max hem de Sum fonksiyonlarını çağırın ve sonuçları yazdırın.

    Tam sayı girdisi için şunu yazdırın:

    Max (int): [value]
    Sum (int): [value]

    Ondalıklı sayı girdisi için bir ondalık basamakla yazdırın:

    Max (float): [value]
    Sum (float): [value]

Aşağıdaki girdiler sağlanacaktır:

  • Satır 1: Tür göstergesi (int veya float)
  • Satır 2: Değerlerin sayısı (tam sayı)
  • Sonraki satırlar: Her satırda bir değer

Örneğin, şu girdi verildiğinde:

int
4
15
8
23
11

Çıktınız şöyle olmalıdır:

Max (int): 23
Sum (int): 57

Ve şu girdi verildiğinde:

float
3
4.5
9.2
6.8

Çıktınız şöyle olmalıdır:

Max (float): 9.2
Sum (float): 20.5

Aynı generic fonksiyonların hem tam sayı hem de ondalıklı sayı verilerini nasıl işlediğine dikkat edin; [T int | float64] tür parametresi, siz mantığı yalnızca bir kez yazarken derleyicinin her kullanım için tür açısından güvenli kod oluşturmasına olanak tanır.

Kopya kağıdı

Generic yapılar, tip güvenliğini korurken birden fazla tiple çalışan yeniden kullanılabilir kodlar yazmanıza olanak tanır. Go 1.18'den önce, her tip için ayrı fonksiyonlara ihtiyacınız vardı veya tip onaylamaları (type assertions) ile boş arayüz (empty interface) kullanıyordunuz.

Tip parametreleri köşeli parantez içinde bildirilir ve bir generic fonksiyonun hangi tipleri kabul edebileceğini belirtir:

func Min[T int | float64](values []T) T {
    min := values[0]
    for _, v := range values {
        if v < min {
            min = v
        }
    }
    return min
}

[T int | float64] söz dizimi, int veya float64 olabilen bir T tip parametresi tanımlar. Boru | operatörü, izin verilen tipleri listeler.

Generic fonksiyonları farklı tiplerle çağırabilirsiniz:

Min([]int{3, 1, 2})           // int ile çalışır
Min([]float64{3.5, 1.2})      // float64 ile çalışır

Derleyici, tip kontrolünü derleme zamanında gerçekleştirerek çalışma zamanı yükü (runtime overhead) olmadan güvenlik sağlar.

Kendin dene

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Tür göstergesini oku
	typeStr, _ := reader.ReadString('\n')
	typeStr = strings.TrimSpace(typeStr)

	// Sayısı oku
	countStr, _ := reader.ReadString('\n')
	count, _ := strconv.Atoi(strings.TrimSpace(countStr))

	if typeStr == "int" {
		// Tam sayı değerlerini oku
		values := make([]int, count)
		for i := 0; i < count; i++ {
			line, _ := reader.ReadString('\n')
			values[i], _ = strconv.Atoi(strings.TrimSpace(line))
		}

		// TODO: Max ve Sum fonksiyonlarını integer slice ile çağır
		// TODO: Sonuçları "Max (int): [value]" ve "Sum (int): [value]" formatında yazdır

	} else if typeStr == "float" {
		// Ondalıklı sayı değerlerini oku
		values := make([]float64, count)
		for i := 0; i < count; i++ {
			line, _ := reader.ReadString('\n')
			values[i], _ = strconv.ParseFloat(strings.TrimSpace(line), 64)
		}

		// TODO: Max ve Sum fonksiyonlarını float64 slice ile çağır
		// TODO: Sonuçları virgülden sonra bir basamak olacak şekilde "Max (float): [value]" ve "Sum (float): [value]" formatında yazdır
	}
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler