Dalam bahasa Swift, untuk menginisialisasi instance, kita harus mengisi semua bidang kelas itu, dan baru kemudian memanggil superconstructor:
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)
}
}
Bagi saya sepertinya mundur, karena instance self
harus dibuat sebelum memberikan nilai ke bidangnya, dan kode itu memberi kesan seolah-olah rantai hanya terjadi setelah penugasan. Selain itu, superclass tidak memiliki sarana hukum untuk membaca atribut yang diperkenalkan subkelasnya, sehingga keselamatan tidak diperhitungkan dalam kasus ini.
Juga, banyak bahasa lain, seperti JavaScript, dan bahkan Objective C, yang merupakan nenek moyang spiritual Swift, membutuhkan panggilan berantai sebelum mengakses self
, bukan setelahnya.
Apa alasan di balik pilihan ini untuk mengharuskan bidang harus didefinisikan sebelum memanggil superconstructor?
sumber
self
.Jawaban:
Di C ++, ketika Anda membuat objek yang diturunkan, itu dimulai sebagai objek basis saat konstruktor basis berjalan, jadi pada saat konstruktor basis berjalan, anggota yang diturunkan bahkan tidak ada. Jadi mereka tidak perlu diinisialisasi, dan mereka tidak mungkin diinisialisasi. Hanya ketika konstruktor Basis selesai, objek diubah menjadi objek Turunan dengan banyak bidang yang tidak diinisialisasi yang kemudian Anda inisialisasi.
Di Swift, saat Anda membuat objek yang diturunkan, itu adalah objek yang diturunkan dari awal. Jika metode diganti, maka metode Base init sudah akan menggunakan metode yang diganti, yang mungkin mengakses variabel anggota turunan. Oleh karena itu semua variabel anggota yang diturunkan harus diinisialisasi sebelum metode Base init dipanggil.
PS. Anda menyebutkan Objective-C. Di Objective-C, semuanya secara otomatis diinisialisasi ke 0 / nil / NO. Tetapi jika nilai itu bukan nilai yang benar untuk menginisialisasi variabel, maka metode Base init dapat dengan mudah memanggil metode yang diganti dan menggunakan variabel yang belum diinisialisasi dengan nilai 0 bukannya nilai yang benar. Di Objective-C, itu bukan pelanggaran aturan bahasa (begitulah didefinisikan untuk bekerja) tetapi jelas bug dalam kode Anda. Di Swift, bug itu tidak diizinkan oleh bahasa.
PS. Ada komentar "apakah itu objek yang diturunkan dari awal, atau tidak dapat diamati karena aturan bahasa"? Kelas Derived telah menginisialisasi anggotanya sendiri sebelum metode Base init dipanggil, dan anggota yang diturunkan ini mempertahankan nilainya. Jadi itu adalah objek Derived pada saat Base init dipanggil, atau kompiler harus melakukan sesuatu yang agak aneh. Dan tepat setelah metode Base init menginisialisasi semua anggota instance Base, ia dapat memanggil fungsi yang ditimpa dan yang akan membuktikannya adalah turunan dari kelas turunan.
sumber
Ini berasal dari aturan keselamatan Swift, seperti yang dijelaskan dalam bagian Inisialisasi Dua Fase pada halaman Inisialisasi dokumen bahasa .
Ini memastikan bahwa setiap bidang diatur sebelum digunakan (esp. Pointer, untuk menghindari crash).
Swift mencapai ini dengan urutan inisialisasi dua fase: Setiap penginisialisasi harus menginisialisasi semua bidang instance, kemudian memanggil penginisialisasi superclass untuk melakukan hal yang sama, dan hanya setelah itu terjadi pohon adalah inisialisasi ini diizinkan untuk membiarkan
self
pointer keluar, sebut instance metode, atau baca nilai properti instance.Mereka kemudian dapat melakukan inisialisasi lebih lanjut, meyakinkan bahwa objek tersebut terbentuk dengan baik. Secara khusus, semua pointer non-opsional akan memiliki nilai yang valid. nihil tidak berlaku untuk mereka.
Sasaran C tidak jauh berbeda kecuali bahwa 0 atau nil selalu merupakan nilai yang valid, jadi inisialisasi fase pertama dilakukan oleh pengalokasi hanya mengatur semua bidang ke 0. Juga, Swift memiliki bidang yang tidak dapat diubah, sehingga mereka harus diinisialisasi dalam fase satu . Dan Swift memberlakukan aturan keselamatan ini.
sumber
Mempertimbangkan
Oleh karena itu tidak ada desain sederhana yang membuat kontraktor aman ketika metode virtual diizinkan , Swift menghindari masalah ini dengan memerlukan Inisialisasi Dua Fase, sehingga memberikan keamanan yang lebih baik kepada programmer, sementara juga menghasilkan bahasa yang lebih kompleks.
Jika Anda dapat memecahkan masalah ini dengan cara yang baik, jangan lulus "Pergi", lanjutkan langsung ke pengumpulan PHd Anda ...
sumber