In der Sprache Swift muss man zum Initialisieren einer Instanz alle Felder dieser Klasse ausfüllen und erst dann den Superkonstruktor aufrufen:
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)
}
}
Für mich scheint es rückwärts zu sein, da die Instanz self
vor dem Zuweisen von Werten zu ihren Feldern erstellt werden muss und dieser Code den Eindruck erweckt, als ob die Verkettung erst nach der Zuweisung erfolgt. Abgesehen davon hat die Oberklasse keine legalen Mittel, um die eingeführten Attribute ihrer Unterklasse zu lesen, sodass die Sicherheit in diesem Fall nicht zählt.
Viele andere Sprachen, wie JavaScript und sogar Objective C, das ein etwas spiritueller Vorfahr von Swift ist, erfordern vor dem Zugriff einen Verkettungsaufruf self
, nicht danach.
Was ist der Grund für diese Wahl, dass die Felder definiert werden müssen, bevor der Superkonstruktor aufgerufen wird?
quelle
self
.Antworten:
Wenn Sie in C ++ ein abgeleitetes Objekt erstellen, beginnt es als Basisobjekt, während der Basiskonstruktor ausgeführt wird. Zum Zeitpunkt der Ausführung des Basiskonstruktors sind die abgeleiteten Elemente also nicht einmal vorhanden. Sie müssen also nicht initialisiert werden und konnten möglicherweise nicht initialisiert werden. Erst wenn der Basiskonstruktor fertig ist, wird das Objekt in ein abgeleitetes Objekt mit vielen nicht initialisierten Feldern geändert, die Sie dann initialisieren.
Wenn Sie in Swift ein abgeleitetes Objekt erstellen, handelt es sich von Anfang an um ein abgeleitetes Objekt. Wenn Methoden überschrieben werden, verwendet die Base init-Methode bereits die überschriebenen Methoden, die möglicherweise auf abgeleitete Elementvariablen zugreifen. Daher sind alle Abgeleitet Membervariablen müssen initialisiert werden , bevor die Basis init - Methode aufgerufen wird.
PS. Sie haben Objective-C erwähnt. In Objective-C wird alles automatisch auf 0 / nil / NO initialisiert. Wenn dieser Wert jedoch nicht der richtige Wert zum Initialisieren einer Variablen ist, kann die Base init-Methode leicht eine Methode aufrufen, die überschrieben wird und die noch nicht initialisierte Variable mit dem Wert 0 anstelle des korrekten Werts verwendet. In Objective-C ist dies kein Verstoß gegen die Sprachregeln (so wird es definiert), sondern offensichtlich ein Fehler in Ihrem Code. In Swift ist dieser Fehler in der Sprache nicht zulässig.
PS. Es gibt einen Kommentar "Ist es von Anfang an ein abgeleitetes Objekt oder kann es aufgrund von Sprachregeln nicht beobachtet werden?" Die abgeleitete Klasse hat ihre eigenen Mitglieder initialisiert, bevor die Base init-Methode aufgerufen wird, und diese abgeleiteten Mitglieder behalten ihre Werte bei. Entweder handelt es sich zum Zeitpunkt des Aufrufs von Base init um ein abgeleitetes Objekt, oder der Compiler müsste etwas ziemlich Seltsames tun. Und direkt nachdem die Base init-Methode alle Base-Instanzmitglieder initialisiert hat, kann sie überschriebene Funktionen aufrufen, was beweist, dass es sich um eine Instanz der abgeleiteten Klasse handelt.
quelle
Das kommt von Swift der Sicherheitsbestimmungen, wie im Abschnitt Zwei-Phasen Initialisierung auf der Sprache doc Initialisierungsseite .
Es stellt sicher, dass jedes Feld vor der Verwendung festgelegt wird (insbesondere Zeiger, um Abstürze zu vermeiden).
Swift erreicht dies mit einer zweiphasigen Initialisierungssequenz: Jeder Initialisierer muss alle seine Instanzfelder initialisieren und dann einen Superklasseninitialisierer aufrufen, um dies ebenfalls zu tun. Erst wenn dies im Baum geschieht, dürfen diese Initialisierer den
self
Zeiger entkommen lassen und die Instanz aufrufen Methoden oder lesen Sie die Werte der Instanzeigenschaften.Sie können dann eine weitere Initialisierung durchführen, um sicherzustellen, dass das Objekt gut geformt ist. Insbesondere haben alle nicht optionalen Zeiger gültige Werte. Null ist für sie nicht gültig.
Ziel C ist nicht viel anders, außer dass 0 oder Null immer ein gültiger Wert ist. Daher erfolgt die Initialisierung der ersten Phase durch den Allokator, der nur alle Felder auf 0 setzt. Außerdem verfügt Swift über unveränderliche Felder, sodass diese in Phase 1 initialisiert werden müssen . Und Swift setzt diese Sicherheitsregeln durch.
quelle
Erwägen
Daher gibt es kein einfaches Design, das den Auftragnehmer sicher macht, wenn virtuelle Methoden zulässig sind. Swift vermeidet diese Probleme, indem es eine zweiphasige Initialisierung erfordert, wodurch der Programmierer besser geschützt wird und gleichzeitig eine komplexere Sprache entsteht.
Wenn Sie diese Probleme auf nette Weise lösen können, übergeben Sie nicht "Go", sondern fahren Sie direkt mit der Sammlung Ihrer Doktorarbeit fort.
quelle