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.
Görev
KolayGo'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
Valuefield'ına sahip,Ttüründe generic bir structWrapper[T any]Create et.Sarmalanmış değeri returns eden
Wrapper[T]üzerinde birGetmethod'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) UCreate et. Bu function'ın çıktı türü için kendiUtype 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 functionTransformToString[T any](w Wrapper[T]) stringCreate et.main.go: Geçici çözüm desenini farklı dönüşümlerle göster.Bir type indicator (
intveyastring) oku, ardından bir değer oku. Uygun türde birWrapperCreate et.intgirdisi için: BirWrapper[int]Create et, ardından değeri iki katına çıkarmak içinTransformkullan (bir int returns eder) ve string representation elde etmek içinTransformToStringkullan.stringgirdisi için: BirWrapper[string]Create et, ardından string'in length'ini elde etmek içinTransformkullan (bir int returns eder) ve string representation elde etmek içinTransformToStringkullan.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 (
intveyastring) - Line 2: Değer
Örneğin, şu verildiğinde:
int
25Çıktın şu olmalıdır:
Original: 25
Transformed: 50
As String: 25Ve şu verildiğinde:
string
Hello WorldÇıktın şu olmalıdır:
Original: Hello World
Transformed: 11
As String: Hello WorldTemel çı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
}
}
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 PoolKendi başına pratik yap: Online Go derleyicisi