Swift neden ilk önce uygun sınıfları alt sınıfı başlatmaktadır?


9

Swift dilinde, bir örneği başlatmak için, o sınıfın tüm alanlarını doldurmak ve ancak o zaman süper yapıcı çağırmak gerekir:

class Base {
    var name: String

    init(name: String) {
        self.name = name
    }
}

class Derived: Base {
    var number: Int

    init(name: String, number: Int) {
        // won't compile if interchange lines
        self.number = number
        super.init(name)
    }
}

Benim için geriye doğru görünüyor, çünkü örneğin selfalanlarına değer atamadan önce örneğin oluşturulması gerekiyor ve bu kod zincirleme sadece atamadan sonra gerçekleşiyormuş gibi bir izlenim bırakıyor . Bunun dışında, üst sınıfın alt sınıfının getirdiği nitelikleri okumak için yasal bir yolu yoktur, bu nedenle bu durumda güvenlik dikkate alınmaz.

Ayrıca, JavaScript ve hatta Swift'in biraz manevi atası olan Objective C gibi diğer birçok dil, erişmeden önce zincirleme çağrıyı gerektirir self, sonra değil.

Süper yapılandırıcıyı çağırmadan önce alanların tanımlanmasını zorunlu kılmak için bu seçimin ardındaki neden nedir?


İlginç. Sadece zincirleme işleminden sonra, örneğin yöntem çağrılarının (özellikle sanal) yerleştirilebileceği bir kısıtlama var mı? C # 'da, bir alt sınıfın alanlarına varsayılan değer verilir, sonra zincirleme / üst sınıf yapı, daha sonra bunları gerçek, IIRC için
başlatabilirsiniz

3
Buradaki nokta, sınırsız erişime izin vermeden önce tüm alanları başlatmanız gerektiğidir self.
CodesInChaos

@ErikEidt: Swift'te yalnızca isteğe bağlı alanlar otomatik olarak sıfır değerine başlatılır.
gnasher729

Yanıtlar:


9

C ++ 'da, Türetilmiş bir nesne oluşturduğunuzda, Base kurucusu çalışırken Base nesnesi olarak başlar, bu nedenle Base kurucusu çalışırken, Türetilmiş üyeler bile yoktur. Bu yüzden başlatılmaları gerekmez ve muhtemelen başlatılamazlar. Yalnızca Base yapıcısı tamamlandığında, nesne daha sonra başlattığınız birçok başlatılmamış alanı olan bir Türetilmiş nesneye dönüştürülür.

Swift'te, Türetilmiş bir nesne oluşturduğunuzda, bu başlangıçtan Türetilmiş bir nesnedir. Yöntemler geçersiz kılınırsa, Base init yöntemi, Türetilmiş üye değişkenlere erişebilecek geçersiz kılınmış yöntemleri zaten kullanır. Bu nedenle tüm Türetilmiş üye değişkenler gerekir Taban init yöntemi çağrılmadan önce başlatılmalıdır.

PS. Objective-C'den bahsettiniz. Objective-C'de her şey otomatik olarak 0 / nil / NO olarak başlatılır. Ancak bu değer bir değişkeni başlatmak için doğru değer değilse, Base init yöntemi geçersiz kılınan bir yöntemi kolayca çağırabilir ve henüz başlatılmamış değişkeni doğru değer yerine 0 değeriyle kullanabilir. Objective-C'de bu, dil kurallarının ihlali değildir (çalışmak için bu şekilde tanımlanır), ancak kodunuzdaki bir hata olduğu açıktır. Swift'te, bu hataya dil tarafından izin verilmez.

PS. "En baştan türetilmiş bir nesne mi, yoksa dil kuralları nedeniyle gözlemlenemiyor mu?" Derived sınıfı, Base init yöntemi çağrılmadan önce kendi üyelerini başlattı ve bu Derived üyeleri değerlerini korudu. Yani ya o olduğunu Baz init denir anda Türetilmiş nesne veya derleyici oldukça tuhaf bir şey yapmak zorunda kalacaktı. Base init yöntemi tüm Base örnek üyelerini başlattıktan hemen sonra, geçersiz kılınan işlevleri çağırabilir ve bu türetilmiş sınıfın bir örneği olduğunu kanıtlar.


Çok mantıklı. Bir örnek ekleme özgürlüğünü aldım. Bu noktayı belirsiz veya yanlış anladıysam geri dönmekten çekinmeyin.
Zomagk

Başlangıçtan türetilmiş bir nesne mi, yoksa dil kuralları bunu gözlemlenemez kılıyor mu? Sanırım ikincisi.
Tekilleştirici

9

Bu , dil belgesinin Başlatma sayfasındaki İki Fazlı Başlatma bölümünde açıklandığı gibi Swift'in güvenlik kurallarından gelir .

Her alanın kullanımdan önce ayarlanmasını sağlar (çökmeleri önlemek için özellikle işaretçiler).

Swift bunu iki aşamalı bir başlatma sırası ile başarıyor: Her başlatıcı, tüm örnek alanlarını başlatmalı, daha sonra aynı şekilde yapmak için bir üst sınıf başlatıcı çağırmalı ve ancak bundan sonra ağaç bu başlatıcıların selfişaretçinin kaçmasına izin vermesine izin vermeli , çağrı örneği yöntemleri veya örnek özelliklerinin değerlerini okuyun.

Daha sonra, nesnenin iyi biçimlendirildiğinden emin olarak daha fazla başlatma yapabilirler. Özellikle, isteğe bağlı olmayan tüm işaretçiler geçerli değerlere sahip olacaktır. nil onlar için geçerli değil.

Amaç C, 0 veya sıfırın her zaman geçerli bir değer olması dışında çok farklı değildir, bu nedenle ilk aşama başlatma, tüm alanları 0 olarak ayarlayan ayırıcı tarafından yapılır. Ayrıca, Swift'in değiştirilemez alanları vardır, bu nedenle birinci aşamada başlatılmaları gerekir . Swift bu güvenlik kurallarını uygular.


Tabii ki, MI ile çok daha zor olurdu.
Tekilleştirici

3

Düşünmek

  • Temel sınıfta tanımlanan sanal bir yöntem türetilmiş sınıfta yeniden tanımlanabilir.
  • Temel sınıfın yüklenicisi bu sanal yöntemi doğrudan veya dolaylı olarak adlandırabilir.
  • Yeniden tanımlanmış sanal yöntem (türetilmiş sınıfta) türetilmiş sınıftaki bir alanın türetilmiş sınıf yüklenicisinde doğru şekilde ayarlanmasına bağlı olabilir.
  • Türetilmiş sınıfın yüklenicisi, temel sınıfta temel sınıf yüklenicisinde ayarlanan alanlara bağlı bir yöntem çağırabilir.

Bu nedenle , sanal yöntemlere izin verildiğinde yükleniciyi güvenli hale getiren basit bir tasarım yoktur , Swift, İki Fazlı Başlatma gerektirerek bu sorunlardan kaçınır, böylece programcıya daha iyi güvenlik sağlarken, daha karmaşık bir dille sonuçlanır.

Bu sorunları güzel bir şekilde çözebilirseniz, "Git" geçmeyin, doğrudan PHd koleksiyonunuza devam edin…

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.