ProgramlamaBackend Geliştirici

Go'da anonim yapıların iç içeliği (struct embedding) nasıl çalışır ve embedding, yapıdaki sıradan bir alandan neyle farklıdır?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap.

Sorunun Tarihi

Go dilinde kompozisyon desteği embedding mekanizması aracılığıyla sağlanır — bu, bir yapının başka bir yapının içine açık bir alan adı olmadan dahil edilmesi imkanıdır. Bu yaklaşımın, mirası "kendi tarzında" modellemeye olanak tanıması ve dilin sadeliğini koruyarak çoklu mirasla ilgili birçok karmaşıklıktan kaçınması amaçlanmıştır.

Problem

Geliştirici genellikle belirli bir temel yapının davranışını veya arayüzünü karmaşayı artırmadan genişletmek ister. Go'da bunun için genellikle embedding kullanılır; bu, iç içe geçen türün yöntemlerine ve alanlarına doğrudan erişim sağlar, sanki bunlar üst yapı içinde tanımlanmış gibi. Ancak embedding'in kendine has özellikleri vardır ve mekanizmanın yanlış anlaşılması, isim çatışmaları, double embedding ve yöntemlerin yanlış miras alınması gibi beklenmedik hatalara yol açabilir.

Çözüm

Embedding'in doğru ve ihtiyatlı kullanımı daha temiz bir kompozisyon elde etmeyi sağlar. Yöntemlerin ve alanların "bir üst seviyeye" çıkarıldığını ve embedding'in aslında "has-a" (sahiplik) ilişkisini gerçekleştirdiğini hatırlamak gerekir; "is-a" (bir tür olma) ilişkisi değildir. İsim çatışmalarından kaçınılmalı ve yöntem alıcısının nasıl çalıştığına dair bir anlayışa sahip olunmalıdır.

Kod örneği:

package main import "fmt" type Engine struct { Power int } func (e Engine) Start() { fmt.Println("Motor güçle başladı", e.Power) } type Car struct { Engine // embedding, Engine değil engine Engine gibi bir alan Brand string } func main() { c := Car{Engine: Engine{Power: 200}, Brand: "Toyota"} c.Start() // doğrudan erişilebilir fmt.Println(c.Power) // alan da kaldırılmıştır }

Anahtar özellikler:

  • İçteki embedding türünün yöntemleri ve alanları "yukarıya" çıkarılır
  • Embedding, içe geçmiş tür gerekli yöntemleri sağlıyorsa bir arayüzü gerçekleştirebilir
  • Bu, "is-a" mirası değil, "has-a" kompozisyonudur

Kandırmacalı Sorular.

Embedding çoklu mirası gerçekleştirebilir mi?

Hayır, embedding OOP'deki gibi miras sağlamaz; bu bir kompozisyondur. Bir yapıya birden fazla başka yapı eklenebilir, ancak yöntemler çakıştığında bir birleşim değil, çakışma hatası meydana gelir.

İç içe geçmiş yapıların alanları aynı isimlere sahipse ne olur?

Doğrudan erişimde bir derleme hatası meydana gelir: derleyici hangi alana ulaşacağını bilmez. Gerekirse iç içe geçmiş yapının adı aracılığıyla yol açıkça belirtilmelidir.

Kod örneği:

type A struct {X int} type B struct {X int} type C struct { A B } func main() { c := C{} // c.X = 1 // hata: ambiguous selector c.A.X = 1 // sadece böyle }

Embedding'de yöntemler değerle/göstericiyle aynı şekilde mi yükseltilir?

Hayır. Gösterici alıcıya sahip yöntemler yalnızca yapı da gösterici kullanıyorsa yükseltilir (c := &Car{}). Yapı değer olarak kullanıldığında, gösterici alıcıya sahip yöntemler "yükseltilmeyecek".

Tipik Hatalar ve Antipatternler

  • İç içe yapının yöntemlerinin ve alanlarının kazara "gölgelendiği" durumlar
  • Kompozisyon konseptini ihlal ederek mirası taklit etmek için embedding kullanılması
  • Kompozisyonun açıklık ilkesinin ihlali

Hayattan Bir Örnek

Olumsuz Durum

Derin iç içe yapı kullanılan bir proje, burada embedding çok katmanlı mirası taklit etmek için kullanılıyor. Yeni bir geliştirici, alanın veya yöntemin hangi yapından geldiğini anlamıyor ve tüm proje karmaşık hale geliyor ve "büyülü" bir hale geliyor.

Artılar:

  • Davranışın hızlı derlenmesi

Eksiler:

  • Zayıf okunabilirlik, zor desteklenebilirlik, yapı üzerinde yeniden düzenleme sırasında çatışmalar

Olumlu Durum

Bir arayüzün uygulanması için embedding kullanılıyor; örneğin, Logger arayüzü, Println yöntemine sahip bir tür aracılığıyla embedding ile uygulanıyor ve bu açıkça belgelenmiş ve testlerle kapsanmıştır.

Artılar:

  • Kompozisyonun basitliği, minimum kod şablonu
  • Yöntemlerin ve alanların öngörülebilir bir şekilde yükselmesi

Eksiler:

  • Arayüzün genişletilmesi sırasında çatışmalar hala mümkündür, dikkatli bir yapı gerektirir.