Dans le langage Swift, pour initialiser une instance, il faut remplir tous les champs de cette classe, et ensuite seulement appeler 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)
}
}
Pour moi, cela semble à l'envers, car l'instance doit self
être créée avant d'affecter des valeurs à ses champs, et ce code donne l'impression que le chaînage ne se produit qu'après l'affectation. En dehors de cela, la superclasse n'a aucun moyen légal de lire les attributs introduits de sa sous-classe, donc la sécurité ne compte pas dans ce cas.
En outre, de nombreux autres langages, comme JavaScript et même Objective C, qui est un ancêtre quelque peu spirituel de Swift, nécessitent un chaînage d'appel avant d'accéder self
, pas après.
Quel est le raisonnement derrière ce choix pour exiger que les champs soient définis avant d'appeler le superconstructeur?
self
.Réponses:
En C ++, lorsque vous créez un objet dérivé, il commence en tant qu'objet de base pendant l'exécution du constructeur de base, donc au moment où le constructeur de base s'exécute, les membres dérivés n'existent même pas. Il n'est donc pas nécessaire de les initialiser et il est impossible de les initialiser. Ce n'est que lorsque le constructeur de base est terminé que l'objet est changé en un objet dérivé avec beaucoup de champs non initialisés que vous initialisez ensuite.
Dans Swift, lorsque vous créez un objet dérivé, il s'agit d'un objet dérivé depuis le début. Si les méthodes sont remplacées, la méthode d'initialisation de base utilisera déjà les méthodes substituées, qui pourraient accéder aux variables membres dérivées. Par conséquent, toutes les variables membres dérivées doivent être initialisées avant l'appel de la méthode d'initialisation de base.
PS. Vous avez mentionné Objective-C. Dans Objective-C, tout est automatiquement initialisé à 0 / nil / NO. Mais si cette valeur n'est pas la valeur correcte pour initialiser une variable, la méthode d'initialisation de base pourrait facilement appeler une méthode qui est remplacée et utilise la variable non encore initialisée avec une valeur de 0 au lieu de la valeur correcte. Dans Objective-C, ce n'est pas une violation des règles de langage (c'est ainsi que cela est défini pour fonctionner) mais bien évidemment un bug dans votre code. Dans Swift, ce bogue n'est pas autorisé par la langue.
PS. Il y a un commentaire "est-ce un objet dérivé dès le départ, ou n'est-il pas observable à cause des règles de langage"? La classe Derived a initialisé ses propres membres avant l'appel de la méthode d'initialisation de base, et ces membres dérivés conservent leurs valeurs. Donc , soit il est un objet dérivé au moment de base init est appelé, ou le compilateur aurait à faire quelque chose d' assez bizarre. Et juste après que la méthode init de base a initialisé tous les membres d'instance de base, elle peut appeler des fonctions remplacées et cela prouvera qu'il s'agit d'une instance de la classe dérivée.
la source
Cela vient des règles de sécurité de Swift, comme expliqué dans la section Initialisation en deux phases sur la page Initialisation du doc de langue .
Il garantit que chaque champ est défini avant utilisation (en particulier les pointeurs, pour éviter les plantages).
Swift y parvient avec une séquence d'initialisation en deux phases: chaque initialiseur doit initialiser tous ses champs d'instance, puis appeler un initialiseur de super-classe pour faire de même, et ce n'est qu'après que cela se produit dans l'arborescence que ces initialiseurs sont autorisés à laisser le
self
pointeur s'échapper, appeler l'instance ou lisez les valeurs des propriétés d'instance.Ils peuvent ensuite effectuer une autre initialisation, assurés que l'objet est bien formé. En particulier, tous les pointeurs non facultatifs auront des valeurs valides. nul n'est pas valable pour eux.
L'objectif C n'est pas très différent, sauf que 0 ou nil est toujours une valeur valide, donc l'initialisation de la première phase est effectuée par l'allocateur en mettant simplement tous les champs à 0. De plus, Swift a des champs immuables, ils doivent donc être initialisés dans la phase un . Et Swift applique ces règles de sécurité.
la source
Considérer
Par conséquent, il n'y a pas de conception simple qui sécurise l'entrepreneur lorsque des méthodes virtuelles sont autorisées , Swift évite ces problèmes en exigeant une initialisation en deux phases, offrant ainsi une meilleure sécurité au programmeur, tout en créant un langage plus complexe.
Si vous pouvez résoudre ces problèmes d'une manière agréable, ne passez pas "Go", passez directement à la collecte de votre PHd ...
la source