Ders 13 / 13
Ne Zaman Genellik
Aynı toplam alan hesabı üç yazımla kuruluyor: boş arayüzle üç tip iddiası, genellikle sıfır ama T tek bir somut tipe sabitlenmiş, arayüz sözleşmesiyle yine sıfır ama farklı somut tipler aynı dilimde durabiliyor. Sınırlayıcı ölçüm, T bir arayüze sabitlendiğinde (heterojen bir koleksiyonu kabul etmek için) genelliğin kazancının kaybolduğunu gösteriyor: eleman boyutu 8 bayttan 16 bayta çıkıyor, tıpkı sıradan bir arayüz değeri gibi. Kurs on altı bağın 4'ünü bildirimde, 4'ünü kullanım yerinde, 8'ini değerin içinde buldu.
İçindekiler
Genel Veri Yapıları dersi genelliğin üç ders boyunca hep kaynağın içinde kaldığını gösterdi: tip parametresi ya çıkarıldı ya bildirimde açıkça yazıldı, ama hiçbir zaman değere girmedi. Arayüz konusu tam tersini ölçmüştü — dinamik tip değerin içinde taşınıyor ve ancak değere sorularak okunabiliyordu. Bu kapanış dersi iki yazımı, ve aralarında duran arayüz sözleşmesini, aynı işi üç kez yaparak yan yana koyar: bir toplam alan hesabı boş arayüzle, genellikle ve arayüz sözleşmesiyle kurulur, ve üçünde de bağın nerede kurulduğu sayılır.
Kursun üçüncü iddiası buydu: genellik ile arayüz aynı işi iki ayrı yerde yapıyor. Genellikte bağ bildirimde ve kullanım yerinde kurulur, değere hiç girmez; arayüzde bağ değere girer. Bu ders bu farkı ilk kez doğrudan koşturarak, aynı hesaplamayı üç kez yazarak, ölçer.
Önceki üç ders genelliği hep kendi başına ölçtü — arayüzle yan yana koymadan. Bu, kursun genel çerçevesine bir borç bıraktı: “genellikte bağ değere girmiyor” iddiası, bir karşılaştırma yapılmadan yalnız bir gözlemdi. Bu ders o borcu kapatıyor: aynı iş hem genellikle hem arayüzle yazılıp aynı koşumda ölçülüyor, ve fark bir iddia olmaktan çıkıp bir sayıya (8 bayta karşı 16 bayt) dönüşüyor.
Aynı İş, Üç Yazım
Ölçülen iş basit: bir koleksiyondaki şekillerin toplam alanını hesaplamak. Kare ve
Daire kendi Alan() yöntemini taşıyor; Sekil arayüzü bu tek yöntemi listeliyor. Bu iş
bilinçli seçildi: alan hesabı tipe göre gerçekten değişiyor — bir karenin alanı
kenarın karesi, bir dairenin alanı yarıçapın karesiyle bir sabitin çarpımı — ama toplama
işleminin kendisi her tip için aynı. Üç yazımın da başarması gereken iş bu yüzden iki
parçaya ayrılıyor: tipe özgü kısım (Alan()in kendi gövdesi) ve tipten bağımsız kısım
(toplamı biriktirmek).
// uc.go — ayni is uc yazimla: bos arayuz, genellik, arayuz sozlesmesi
package main
import (
"fmt"
"unsafe"
)
type Kare struct{ Kenar float64 }
func (k Kare) Alan() float64 { return k.Kenar * k.Kenar }
type Daire struct{ YariCap float64 }
func (d Daire) Alan() float64 { return 3.14159 * d.YariCap * d.YariCap }
type Sekil interface{ Alan() float64 }
// 1) bos arayuzle: her eleman icin bir tip iddiasi (tip anahtari dali) gerekiyor.
func toplamAlanAny(d []any) (toplam float64, iddiaSayisi int) {
for _, e := range d {
switch v := e.(type) {
case Kare:
iddiaSayisi++
toplam += v.Alan()
case Daire:
iddiaSayisi++
toplam += v.Alan()
}
}
return
}
// 2) genellikle: govde her T icin ayni, T homojen kaldigi surece hic tip iddiasi yok.
func toplamAlanGenel[T Sekil](d []T) (toplam float64) {
for _, e := range d {
toplam += e.Alan()
}
return
}
// 3) arayuz sozlesmesiyle: farkli somut tipler ayni dilimde, hicbir tip iddiasi yok.
func toplamAlanArayuz(d []Sekil) (toplam float64) {
for _, e := range d {
toplam += e.Alan()
}
return
}
func main() {
fmt.Println("-- ayni is, uc yazim --")
karisik := []any{Kare{Kenar: 2}, Daire{YariCap: 1}, Kare{Kenar: 3}}
tAny, iddia := toplamAlanAny(karisik)
fmt.Printf("bos arayuz toplam=%.4f tip iddiasi=%d bildirim satiri=0\n", tAny, iddia)
homojen := []Kare{{Kenar: 2}, {Kenar: 3}}
tGenel := toplamAlanGenel(homojen)
fmt.Printf("genellik toplam=%.4f tip iddiasi=0 bildirim satiri=1 (kisit)\n", tGenel)
sozlesmeli := []Sekil{Kare{Kenar: 2}, Daire{YariCap: 1}, Kare{Kenar: 3}}
tArayuz := toplamAlanArayuz(sozlesmeli)
fmt.Printf("arayuz toplam=%.4f tip iddiasi=0 bildirim satiri=1 (arayuz)\n", tArayuz)
fmt.Println()
fmt.Println("-- sinirlayici olcum: T bir arayuze sabitlenince kazanc kayboluyor --")
heterojen := []Sekil{Kare{Kenar: 2}, Daire{YariCap: 1}}
tDejenere := toplamAlanGenel(heterojen)
fmt.Printf("toplamAlanGenel[Kare](homojen) T=Kare eleman boyutu=%d bayt sonuc=%.4f\n",
unsafe.Sizeof(homojen[0]), tGenel)
fmt.Printf("toplamAlanGenel[Sekil](heterojen) T=Sekil eleman boyutu=%d bayt sonuc=%.4f\n",
unsafe.Sizeof(heterojen[0]), tDejenere)
}
-- ayni is, uc yazim -- bos arayuz toplam=16.1416 tip iddiasi=3 bildirim satiri=0 genellik toplam=13.0000 tip iddiasi=0 bildirim satiri=1 (kisit) arayuz toplam=16.1416 tip iddiasi=0 bildirim satiri=1 (arayuz) -- sinirlayici olcum: T bir arayuze sabitlenince kazanc kayboluyor -- toplamAlanGenel[Kare](homojen) T=Kare eleman boyutu=8 bayt sonuc=13.0000 toplamAlanGenel[Sekil](heterojen) T=Sekil eleman boyutu=16 bayt sonuc=7.1416
GN13. İlk üç satır aynı hesaplamanın üç kaynağını karşılaştırıyor. Boş arayüz yazımı
üç elemanın üçü için de bir tip iddiası (tip anahtarının bir dalı) çalıştırıyor ve hiçbir
arayüz bildirmiyor — sözleşme kaynakta hiçbir yerde yazılı değil, yalnız switch içindeki
case dalları örtük olarak hangi tiplerin bekleneceğini söylüyor. Genellik yazımı sıfır
tip iddiasıyla çalışıyor ama homojen yalnız Kare içeriyor — T, Genel Veri Yapıları
dersinin ölçtüğü gibi, çağıranın bildiriminde tek bir somut tipe sabitleniyor. Arayüz
yazımı da sıfır tip iddiasıyla çalışıyor ve üstelik Kare ile Daireyi aynı dilimde
taşıyabiliyor — sozlesmeli ikisini birden içeriyor, homojen içeremezdi.
Sınırlayıcı Ölçüm: T Bir Arayüze Sabitlenince Kazanç Kayboluyor
GN14. Son iki satır genelliğin sınırını gösteriyor. toplamAlanGenel, kısıtı bir
yöntem listesi olduğu için, Tyi bir arayüz tipiyle de örnekleyebiliyor —
toplamAlanGenel[Sekil](heterojen) derleniyor ve Kare ile Daireyi karışık bir
dilimde kabul ediyor. Ama bunun bedeli ölçülüyor: T=Kare iken her eleman 8 bayt (yalnız
Kenar alanının kendisi), T=Sekil iken her eleman 16 bayt — arayüz çiftinin taşıdığı
tip işaretçisi ile veri işaretçisinin toplamı. Tyi bir arayüze sabitlemek, genelliğin
sıfır maliyetli sözünü bozuyor: kod artık toplamAlanArayuzdan hiçbir farkı olmayan bir
şey çalıştırıyor, yalnız bunu bir tip parametresinin arkasına gizlemiş durumda.
toplamAlanGenelin gövdesi iki çağrıda da harfi harfine aynı kaldı — for _, e := range d { toplam += e.Alan() } satırı ne T=Kare ne T=Sekil için değişti. Değişen yalnız
Tnin ne olduğu, ve bu değişim eleman boyutunu iki katına çıkardı. Bu, genelliğin
tanımının kendisinden geliyor: bir genel gövde, tek bir kaynaktan, örneklendiği her T
için aynı işlemi çalıştırır. T=Kare iken bu işlem Kare.Alan()i doğrudan, ek bir
katman olmadan çağırıyor; T=Sekil iken aynı işlem artık bir arayüz değeri üzerinden
dolaylı bir yöntem çağrısı yapıyor — kaynakta hiçbir satır değişmese de, çalışma zamanında
olan biten değişiyor.
Bu, kursun sorusuna kesin bir yanıt veriyor: genellik her zaman kazanmaz. Bir koleksiyonun
bütün elemanları aynı somut tipteyse ve üzerlerinde yapılan işlem her tip için aynıysa,
genellik hem sıfır tip iddiası hem sıfır ek bayt sağlıyor. Elemanlar farklı somut tipler
taşımak zorundaysa — davranış tipe göre gerçekten değişmesi gerekiyorsa — iki seçenek
kalıyor: Tyi bir arayüze sabitleyip genelliğin kazancından vazgeçmek, ya da baştan
arayüz yazmak. İkincisi daha dürüst bir yazım, çünkü kaynak zaten neyin olacağını —
birden fazla somut tipin aynı yerde duracağını — söylüyor. Genel bir gövde, tanımı
gereği, örneklendiği her T için aynı kalıyor; farklı Tler için farklı davranmasını
istemek, genelliğin kendisiyle çelişiyor.
Kurs Kapanışı
Arayüzler, Hatalar ve Genellikler kursu tek bir soruyla açıldı: Go’da bir tipin bir arayüzü karşıladığı hiçbir yerde yazmıyor — öyleyse bu bağ nerede kuruluyor? On üç ders bu soruyu üç düzenekte sordu: arayüzlerde (örtük gerçekleştirim, boş arayüz, tip iddiası, gömme, tüketici tarafında tanımlama), hata değerlerinde (hata arayüzü, nöbetçi hatalar, sarmalama, panik) ve genelliklerde (tip parametresi, tip kısıtı, genel veri yapıları, ve bu derste üçünün karşılaştırılması).
Birinci iddia doğrulandı: on altı bağın sekizi değerin içinde taşınıyor, çünkü Go’nun arayüz değeri bir çift — hem somut tip hem veri. İkinci iddia doğrulandı: dört bağ kullanım yerinde kuruluyor ve kaynak, bir tipin bir arayüzü karşıladığını hiçbir yerde söylemiyor. Üçüncü iddia bu derste doğrudan koşturuldu: genellik ile arayüz aynı işi iki ayrı yerde yapıyor — genellikte bağ bildirimde ve kullanım yerinde kalıyor, arayüzde değere giriyor — ve genelliğin bu kazancı, tip parametresi bir arayüze sabitlendiği anda kayboluyor.
Bu üç düzenekten biri, “kullanım yeri”, bir uyarı taşıyor: kullanım yeri derleyicinin baktığı yerdir, kaynağın işaret ettiği yer değildir. Genel Fonksiyonlar dersi bunu doğrudan derleyiciye sorarak — kaynağı geçici bir pakete yazıp yalnız geçip geçmediğini okuyarak — kanıtladı; Genel Veri Yapıları ve Tip Kısıtları dersleri de aynı yöntemi kullandı. Dolaylı bir kanıt (yalnız kaynakta bir sözleşmenin yazılı olmadığını göstermek) ile doğrudan bir kanıt (derleyicinin nerede durduğunu koşturarak görmek) arasındaki bu fark, kursun kendi ölçüm disiplininin bir parçası: bir ders “kullanım yerinde kuruluyor” diyorsa, ya derleyiciyi çağırıp nerede durduğunu göstermeli, ya da kanıtın dolaylı olduğunu açıkça yazmalıdır.
Kurs aşırı bir genelleme yapmadan kapanıyor: bu üç düzenek (bildirim, kullanım yeri, değer) Go’nun bütün tip sistemini kapsamıyor, yalnız on üç dersin sorduğu tek soruya — bu bağ nerede kuruluyor? — verilen yanıtları sınıflıyor. Aşağıdaki tablo bu on üç yanıtı tek satırda topluyor; bir satır boş bırakıldı, çünkü karşılık geldiği ders bu kapanış yazıldığı sırada henüz diskte değildi — hücre uydurulmadı.
| Ders | Ölçülen bağ | Kurulduğu yer (bildirim · kullanım yeri · değer) | Sınırlayıcı ölçüm |
|---|---|---|---|
| Arayüz Kavramı | Bir tipin bir arayüzü örtük karşılaması; küçük arayüz ilkesi | kullanım yeri (4/4/8 dağılımı burada üretildi) | Derleme zamanı uyum kanıtı bağı bildirime taşır, kanıt yokken derleyici sessiz kalır |
Boş Arayüz ve any |
Boş arayüzün tip bilgisini değere taşıması | değer | nil işaretçili arayüz nil değildir |
| Tip İddiası ve Tip Anahtarı | Değere sorma: iki yanıtlı iddia, tip anahtarının seçtiği dal | değer | Aynı değer hem somut hem arayüz dalına uyabilir, seçilen dal yazılış sırasına bağlı |
| Arayüz Gömme | Sözleşme bileşimi | bildirim | Gömme yalnız sözleşmeyi birleştirir, gerçekleştirimi birleştirmez |
| Arayüz Tasarımı | Aynı somut tip, tüketicilerin tanımladığı dört bağımsız arayüzü karşılıyor; kaynağında sıfır atıf var | kullanım yeri | Aynı imzalı iki ayrı adlı arayüz örtük eşdeğer olur; eşdeğerlik ancak imza ayrılınca kırılır |
| Hata Arayüzü | Hatanın örtük karşılanan bir değer olması | kullanım yeri + değer | nil olmayan arayüz nil somut değer taşıyabilir |
| Nöbetçi Hatalar | Hata kimliğinin değerde durması | değer | Kimlik değişince çağıran sessizce yanlış dala düşer, uyarı üretilmez |
| Hata Sarmalama ve Çözme | Zincirin değerde taşınması | değer | %v kullanmak zinciri koparır, metin aynı kalır |
| Panik ve Kurtarma | Paniğin imzada hiçbir iz bırakmaması | (bağ kurulmuyor) | Kurtarma paniği yok etmez, taşır; kurtarılan değer yazılmazsa bilgi tümüyle kaybolur |
| Genel Fonksiyonlar | Tip parametresinin çağrı yerinde çıkarılması | kullanım yeri | Kısıtsız T ile == ve + yazılamaz |
| Tip Kısıtları | Kısıtın tip kümesi listelemesi | bildirim | Tip kümesi terimli arayüz yalnız kısıt konumunda geçerli |
| Genel Veri Yapıları | Örneklemenin çağıranın bildiriminde durması | bildirim | Karşılaştırılabilirlik kapsayıcının alan yapısına da bağlı |
| Ne Zaman Genellik | Aynı işin üç yazımda nerede bağlandığı | (üçünün karşılaştırması) | T bir arayüze sabitlenince genelliğin kazancı kayboluyor |
Kurs boyunca ölçülen üç düzenek, sonuçta, tek bir alışkanlığa iniyor: bir kaynağı okurken “bu bağın nerede kurulduğu” sorusunu sormak. Bir bildirim satırı arandığında bulunuyorsa bağ oradadır; bulunmuyorsa iki yer kalıyor — ya derleyicinin kullanım yerinde kurduğu bir bağ (ki bunu görmenin tek yolu derleyiciyi çağırmaktır), ya da yalnız çalışan değere sorularak öğrenilebilecek bir bağ. Bu üç soruyu sırayla sormak, Go’nun tip sistemini okurken kaynağın söylediğiyle söylemediğini ayırmanın ölçülebilir bir yolu.
Özet
- Aynı toplam alan hesabı üç yazımla kuruldu: boş arayüz üç tip iddiası gerektirdi, genellik ve arayüz sıfır tip iddiasıyla çalıştı.
- Genellik yalnız
Ttek bir somut tipe sabitlendiğinde sıfır maliyetli kalıyor;Tbir arayüze sabitlenince eleman boyutu 8 bayttan 16 bayta çıkıyor ve kazanç kayboluyor. - Davranış tipe göre gerçekten değişmesi gerekiyorsa arayüz gerekiyor, çünkü genel bir
gövde örneklendiği her
Tiçin aynı kalıyor. - Kurs boyunca ölçülen on altı bağın dördü bildirimde, dördü kullanım yerinde, sekizi değerin içinde kuruldu; bu dağılım Go’nun tip sistemini değil, yalnız bu on üç dersin sorduğu soruyu sınıflıyor.
- Genellik ile arayüz aynı işi iki ayrı yerde yapıyor: genellikte bağ değere hiç girmiyor, arayüzde giriyor — ve bu fark, ne zaman hangisinin seçileceğinin ölçülebilir karşılığı.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.