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.
Görev
KolayGo'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.Ttüründe tek birValuealanına sahip genel bir yapı (struct) olanWrapper[T any]oluşturun.Wrapper[T]üzerinde, kapsulenen değeri döndüren birGetmetodu 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) Uoluşturun. Bu fonksiyonun çıktı türü için kendi tür parametresiU'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 olanTransformToString[T any](w Wrapper[T]) stringoluşturun.main.go: Farklı dönüşümlerle bu çözüm modelini gösterin.Bir tür göstergesi (
intveyastring) okuyun, ardından bir değer okuyun. Uygun türde birWrapperoluşturun.intgirişi için: BirWrapper[int]oluşturun, ardından değeri ikiye katlamak için (bir int döndürerek)Transformkullanın ve dize temsilini almak içinTransformToStringkullanın.stringgirişi için: BirWrapper[string]oluşturun, ardından dizenin uzunluğunu almak için (bir int döndürerek)Transformkullanın ve dize temsilini almak içinTransformToStringkullanı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 (
intveyastring) - 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: 25Ve şu verildiğinde:
string
Hello WorldÇıktınız şöyle olmalıdır:
Original: Hello World
Transformed: 11
As String: Hello WorldBuradaki 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
}
}
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
1Go OOP Temelleri
Harici DosyalarGo Çalışma Alanı ve ModüllerPaketler ve İçe AktarmalarDışa Aktarılan ve Aktarılmayan İsimlerGo'da OOP'ye GirişSınıf Olarak Struct'larStruct'larda Metot TanımlamaPointer ve Değer AlıcılarStruct BaşlatmaYapıcı FonksiyonlarÖzet - Basit Hesap Makinesi4Arayüzler
Arayüzlere GirişÖrtük UygulamaSözleşme Olarak ArayüzBoş Arayüz (any)Tür OnaylamaTür SeçimiArayüz BileşimiStringer ve Error ArayüzleriÖzet - Şekil Hesaplayıcı7Kapsülleme
Dışa Aktarılan ve Aktarılmayan AlanlarPaket Seviyesinde KapsüllemeGetter ve Setter MetotlarıGo'da Bilgi GizlemeÖzet - Öğrenci Kayıtları10Generics (Go 1.18+)
Generics'e GirişTür ParametreleriTür KısıtlamalarıGeneric Struct'larGeneric Metotlar İçin Geçici ÇözümÖzet - Generic Koleksiyon13Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıAbstract Factory KalıbıObserver KalıbıStrategy Kalıbı2Türler ve Struct'lar: Derinlemesine İnceleme
Temel ve Bileşik TürlerÖzel Tür TanımlamalarıStruct EtiketleriAnonim Struct'larİç İçe Geçmiş Struct'larSıfır Değerler ve VarsayılanlarÖzet - Rehber5Kalıtım Yerine Kompozisyon
Go'da Neden Kalıtım YokStruct Gömme TemelleriMetot YükseltmeBirden Fazla Struct GömmeGömme vs AgregasyonGömülü Metotları GölgelemeÖzet - Çalışan Hiyerarşisi8Hata Yönetimi ve OOP
error ArayüzüÖzel Hata TürleriHata Sarmalama (fmt.Errorf)Sentinel Hatalarerrors.Is() ve errors.As()Panic, Defer ve RecoverÖzet - Dosya Ayrıştırıcı3İşaretçiler ve Bellek
Go'da İşaretçi TemelleriStruct İşaretçileriDeğer ile Geçme ve Referans ile Geçmenew() FonksiyonuGo'da Garbage CollectionÖzet - Linked List Oluşturucu6Go'da Polimorfizm
Interface'ler ile PolimorfizmGo'da Duck TypingInterface Karşılama KurallarıPolimorfik KoleksiyonlarDependency InjectionÖzet - Payment Processor9Eşzamanlılık ve OOP
Goroutine TemelleriKanallar ve İletişimTamponlu ve Tamponsuz KanallarSelect İfadesisync.Mutex ve sync.RWMutexsync.WaitGroupThread-Safe Struct TasarımıÖzet - Worker Pool