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 sınırlaması vardır: Bir struct üzerinde kendi tür parametrelerine sahip metotlar tanımlayamazsınız. Jenerik struct’lar harika çalışsa da yeni bir tür parametresi tanıtan bir metot eklenmesine izin verilmez.

Bu kod derlenmez:

type Box[T any] struct {
    Value T
}

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

Çözüm olarak bir yöntem yerine bağımsız bir genel işlev kullanmaktır:

type Box[T any] struct {
    Value T
}

// Normal metot - struct'ın 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
}

Genel yapıların yöntemleri, yapının tür parametresi olan T parametresini yine de kullanabilir. Kısıtlama yalnızca yöntem imzasında ek tür parametrelerinin tanıtılması için geçerlidir.

Bu esnekliğe ihtiyaç duyduğunuzda, yapıyı ilk bağımsız değişkeni olarak alan genel bir işlev aynı sonucu elde eder.

challenge icon

Görev

Kolay

Go'nun generic method'lar üzerindeki kısıtlaması için geçici çözümü gösteren bir veri dönüşümü araç seti oluşturalım! Method'lar yeni type parameter'ları tanımlayamadığından, aynı esnekliği sağlayan bağımsız generic function'lar oluşturacaksın.

Code'unu iki dosya arasında düzenleyeceksin:

  • wrapper.go: Generic container'ını ve dönüşüm function'larını Define et.

    Tek bir Value field'ına sahip, T türünde generic bir struct Wrapper[T any] Create et.

    Sarmalanmış değeri returns eden Wrapper[T] üzerinde bir Get method'u Add et. Bu method, izin verilen struct'ın type parameter'ını kullanır.

    Sarmalayıcının değerine dönüşüm function'ını uygulayan ve sonucu returns eden bağımsız bir generic function Transform[T, U any](w Wrapper[T], fn func(T) U) U Create et. Bu function'ın çıktı türü için kendi U type parameter'ına ihtiyacı vardır; bu nedenle bir method yerine bağımsız bir function olmalıdır.

    Sarmalanmış değeri fmt.Sprintf("%v", ...) kullanarak bir string'e dönüştüren başka bir bağımsız function TransformToString[T any](w Wrapper[T]) string Create et.

  • main.go: Geçici çözüm desenini farklı dönüşümlerle göster.

    Bir type indicator (int veya string) oku, ardından bir değer oku. Uygun türde bir Wrapper Create et.

    int girdisi için: Bir Wrapper[int] Create et, ardından değeri iki katına çıkarmak için Transform kullan (bir int returns eder) ve string representation elde etmek için TransformToString kullan.

    string girdisi için: Bir Wrapper[string] Create et, ardından string'in length'ini elde etmek için Transform kullan (bir int returns eder) ve string representation elde etmek için TransformToString kullan.

    results'ı şu formatta Print et:

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

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

  • Line 1: Type indicator (int veya string)
  • Line 2: Değer

Örneğin, şu verildiğinde:

int
25

Çıktın şu olmalıdır:

Original: 25
Transformed: 50
As String: 25

Ve şu verildiğinde:

string
Hello World

Çıktın şu olmalıdır:

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

Temel çıkarım, Transform'un ilk argüman olarak bir Wrapper[T] alması ve return type için yeni bir type parameter U introduce etmesidir. Struct üzerinde bir method olarak mümkün olmayacak bir şeydir bu. Bu pattern, Go'nun type system kısıtları içinde çalışırken generic dönüşümlerin esnekliğini sağlar.

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" {
		// Tamsayı değerini ayrıştır
		num, _ := strconv.Atoi(value)
		
		// TODO: Ayrıştırılmış sayı ile bir Wrapper[int] oluştur
		
		// TODO: Değeri ikiye katlamak için Transform kullan (ipucu: ikiye katlayan bir fonksiyon geçir)
		
		// TODO: String temsilini almak için TransformToString kullan
		
		// TODO: Sonuçları gerekli formatta yazdır:
		// Original: [value]
		// Transformed: [transformed value]
		// As String: [string representation]
		
		_ = num // num'u kullandığında bu satırı kaldır
	} else if typeIndicator == "string" {
		// TODO: Değer ile bir Wrapper[string] oluştur
		
		// TODO: String'in uzunluğunu almak için Transform kullan (ipucu: len() döndüren bir fonksiyon geç)
		
		// TODO: String temsilini almak için TransformToString kullan
		
		// TODO: Sonuçları gerekli formatta yazdır:
		// Original: [value]
		// Transformed: [transformed value]
		// As String: [string representation]
		
		_ = value // value'yu kullandığında bu satırı kaldı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

Kendi başına pratik yap: Online Go derleyicisi