Menu
Coddy logo textTech

Generic Metotlar İçin Geçici Çözüm

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

Go'nun dikkate değer bir kısıtlaması vardır: bir struct üzerinde kendi tip parametrelerine sahip metotlar tanımlayamazsınız. Generik struct'lar harika çalışsa da, yeni bir tip parametresi sunan bir metot eklemeye izin verilmez.

Bu kod derlenmeyecektir:

type Box[T any] struct {
    Value T
}

// HATA: metodun tip parametreleri olmamalıdır
func (b Box[T]) Convert[U any](fn func(T) U) U {
    return fn(b.Value)
}

Geçici çözüm, bir metot yerine bağımsız bir genel (generic) fonksiyon kullanmaktır:

type Box[T any] struct {
    Value T
}

// Normal metot - yapının (struct) tip parametresini kullanır
func (b Box[T]) Get() T {
    return b.Value
}

// Bağımsız fonksiyon - kendi tip parametrelerine sahip olabilir
func Convert[T, U any](b Box[T], fn func(T) U) U {
    return fn(b.Value)
}

func main() {
    intBox := Box[int]{Value: 42}
    
    // Metodu kullan
    fmt.Println(intBox.Get())  // 42
    
    // Bağımsız fonksiyonu kullan
    strResult := Convert(intBox, func(n int) string {
        return fmt.Sprintf("Number: %d", n)
    })
    fmt.Println(strResult)  // Number: 42
}

Generic struct'lar üzerindeki metotlar, struct'ın tip parametresi olan T'yi hala kullanabilir. Kısıtlama yalnızca metot imzasında ek tip parametreleri tanımlanması durumunda geçerlidir.

Bu esnekliğe ihtiyaç duyduğunuzda, yapıyı (struct) ilk argümanı olarak alan generic bir fonksiyon aynı sonucu verir.

challenge icon

Görev

Kolay

Go'nin genel (generic) metotlar üzerindeki kısıtlamasını aşmaya yönelik bir çözüm gösteren bir veri dönüştürme araç seti oluşturalım! Metotlar yeni tür parametreleri tanıtamadığı için, aynı esnekliği sağlayan bağımsız genel fonksiyonlar oluşturacaksınız.

Kodunuzu iki dosya halinde düzenleyeceksiniz:

  • wrapper.go: Genel kapsayıcınızı ve dönüştürme fonksiyonlarınızı tanımlayın.

    T türünde tek bir Value alanına sahip genel bir yapı (struct) olan Wrapper[T any] oluşturun.

    Wrapper[T] üzerinde, kapsulenen değeri döndüren bir Get metodu ekleyin. Bu metot, yapının kendi tür parametresini kullanır ve buna izin verilir.

    Kapsayıcının değerine dönüştürme fonksiyonunu uygulayan ve sonucu döndüren bağımsız bir genel fonksiyon olan Transform[T, U any](w Wrapper[T], fn func(T) U) U oluşturun. Bu fonksiyonun çıktı türü için kendi tür parametresi U'ya ihtiyacı vardır; bu nedenle bir metot yerine bağımsız bir fonksiyon olmalıdır.

    Kapsulenen değeri fmt.Sprintf("%v", ...) kullanarak bir dizeye dönüştüren başka bir bağımsız fonksiyon olan TransformToString[T any](w Wrapper[T]) string oluşturun.

  • main.go: Farklı dönüşümlerle bu çözüm modelini gösterin.

    Bir tür göstergesi (int veya string) okuyun, ardından bir değer okuyun. Uygun türde bir Wrapper oluşturun.

    int girişi için: Bir Wrapper[int] oluşturun, ardından değeri ikiye katlamak için (bir int döndürerek) Transform kullanın ve dize temsilini almak için TransformToString kullanın.

    string girişi için: Bir Wrapper[string] oluşturun, ardından dizenin uzunluğunu almak için (bir int döndürerek) Transform kullanın ve dize temsilini almak için TransformToString kullanın.

    Sonuçları şu formatta yazdırın:

    Original: [value]
    Transformed: [transformed value]
    As String: [string representation]

Aşağıdaki girişler sağlanacaktır:

  • Satır 1: Tür göstergesi (int veya string)
  • Satır 2: Değer

Örneğin, şu verildiğinde:

int
25

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

Original: 25
Transformed: 50
As String: 25

Ve şu verildiğinde:

string
Hello World

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

Original: Hello World
Transformed: 11
As String: Hello World

Buradaki temel nokta, Transform fonksiyonunun ilk argüman olarak bir Wrapper[T] alması ve dönüş türü için yeni bir tür parametresi U tanıtmasıdır; bu, yapı üzerinde bir metot olarak mümkün olmayan bir şeydir. Bu model, Go'nun tür sistemi kısıtlamaları dahilinde çalışırken size genel dönüşümlerin esnekliğini sağlar.

Kopya kağıdı

Go, genel (generic) struct'lar üzerindeki metotların kendi tür parametrelerini tanıtmasına izin vermez. Metotlar yalnızca struct'ın mevcut tür parametrelerini kullanabilir.

Bu kod derlenmeyecektir:

type Box[T any] struct {
    Value T
}

// ERROR: method must have no type parameters
func (b Box[T]) Convert[U any](fn func(T) U) U {
    return fn(b.Value)
}

Geçici çözüm, metotlar yerine bağımsız genel (generic) fonksiyonlar kullanmaktır:

type Box[T any] struct {
    Value T
}

// Regular method - uses the struct's type parameter
func (b Box[T]) Get() T {
    return b.Value
}

// Standalone function - can have its own type parameters
func Convert[T, U any](b Box[T], fn func(T) U) U {
    return fn(b.Value)
}

func main() {
    intBox := Box[int]{Value: 42}
    
    // Use the method
    fmt.Println(intBox.Get())  // 42
    
    // Use the standalone function
    strResult := Convert(intBox, func(n int) string {
        return fmt.Sprintf("Number: %d", n)
    })
    fmt.Println(strResult)  // Number: 42
}

Genel struct'lar üzerindeki metotlar, struct'ın tür parametresini kullanabilir. Kısıtlama yalnızca metot imzasında ek tür parametreleri tanıtılması için geçerlidir. Bu esnekliğe ihtiyaç duyduğunuzda, struct'ı ilk argümanı olarak alan genel bir fonksiyon kullanın.

Kendin dene

package main

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

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// Tip göstergesini oku
	typeIndicator, _ := reader.ReadString('\n')
	typeIndicator = strings.TrimSpace(typeIndicator)
	
	// Değeri oku
	value, _ := reader.ReadString('\n')
	value = strings.TrimSpace(value)
	
	if typeIndicator == "int" {
		// Tam sayı değerini ayrıştır
		num, _ := strconv.Atoi(value)
		
		// TODO: Ayrıştırılan sayı ile bir Wrapper[int] oluştur
		
		// TODO: Değeri ikiye katlamak için Transform kullan (ipucu: ikiye katlayan bir fonksiyon geçirin)
		
		// TODO: Dize temsilini almak için TransformToString kullan
		
		// TODO: Sonuçları istenen formatta yazdır:
		// Original: [value]
		// Transformed: [transformed value]
		// As String: [string representation]
		
		_ = num // num değişkenini kullandığınızda bu satırı kaldırın
	} else if typeIndicator == "string" {
		// TODO: Değer ile bir Wrapper[string] oluştur
		
		// TODO: Dizenin uzunluğunu almak için Transform kullan (ipucu: len() döndüren bir fonksiyon geçirin)
		
		// TODO: Dize temsilini almak için TransformToString kullan
		
		// TODO: Sonuçları istenen formatta yazdır:
		// Original: [value]
		// Transformed: [transformed value]
		// As String: [string representation]
		
		_ = value // value değişkenini kullandığınızda bu satırı kaldırın
	}
}
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