L'extension ne peut pas contenir de propriété stockée, mais pourquoi la propriété stockée statique peut-elle être définie dans l'extension?
Je n'ai également trouvé aucune documentation mentionnant que la propriété statique est autorisée dans l'extension.
extension String {
static let test = "Test"
static var test2 = "Test2"
}
Les extensions ne peuvent pas contenir de propriétés - instance stockées. Pourquoi? Parce que l'ajout d'une propriété d'instance changerait la taille des instances de ce type. Que se passe-t-il si un module ajoute une extension telle qu'un Int
fait maintenant 2 mots? Que devrait-il alors se passer quand, par exemple, il obtient un Int
d'un autre module où il fait toujours 1 mot?
La raison pour laquelle statique les propriétés stockées sont autorisées dans les extensions est simplement parce qu'elles ont une durée de vie statique; ils existent indépendamment de toute instance du type donné que vous étendez. En réalité, ce ne sont rien de plus que des variables globales stockées, juste des espaces de noms pour un type. Par conséquent, ils peuvent être librement ajoutés sans affecter le code qui a déjà été compilé à leur insu.
Il convient toutefois de noter qu'il existe actuellement trois restrictions sur la définition des propriétés stockées statiques.
static
sur un type génériqueCela nécessiterait un stockage de propriété distinct pour chaque spécialisation individuelle du ou des espaces réservés génériques. Par exemple, avec:
struct S<T> {
static var foo: Int {
return 5
}
static let bar = "" // error: Static stored properties not supported in generic types
}
Tout comme foo
est appelé sur la spécialisation individuelle de S
, par exemple S<Int>.foo
et S<Float>.foo
et pas sur S
lui-même (en fait; S
n'est même pas un type actuellement, il nécessite que T
soit satisfait) ; bar
serait (probablement) le même. Il s'appellerait par exemple S<Int>.bar
, ne pas S.bar
.
Il s'agit d'un détail important car le métatype auquel un membre statique est appelé est transmis au récepteur comme argument implicite self
. Ceci est accessible dans les expressions d'initialisation de propriété statique; leur permettant ainsi d'appeler d'autres méthodes statiques.
Par conséquent, être capable d'appeler le même initialiseur de propriété statique sur différent les spécialisations d'un type générique pourraient créer des valeurs de propriété différentes pour chacune (considérons le cas simple de static let baz = T.self
). Par conséquent, nous avons besoin d'un stockage séparé pour chacun d'eux.
Cependant, cela étant dit, il n'y a aucune vraie raison pour laquelle le compilateur/runtime ne peut pas faire cela, et il pourrait bien le faire dans une future version du langage. Bien qu'un argument contre cela est qu'il peut produire un comportement déroutant dans certains cas.
Par exemple, considérez:
import Foundation
struct S<T> {
static let date = Date()
}
Si le runtime a généré implicitement un nouveau stockage pour date
à chaque fois qu'il est accédé sur une nouvelle spécialisation de S<T>
, puis S<Float>.date
ne serait pas égal à S<Int>.date
; ce qui peut être déroutant et/ou indésirable.
static
dans une extension de protocoleCela découle principalement du point précédent. Une propriété stockée static
dans une extension de protocole nécessiterait un stockage séparé pour chaque type conforme de ce protocole (mais encore une fois; il n'y a aucune raison pour que le compilateur/runtime ne puisse pas faire cela).
Ceci est nécessaire avec les protocoles, car les membres static
dans les extensions de protocole sont pas membres sur le type de protocole lui-même. Ils sont membres sur des types concrets conformes au protocole.
Par exemple, si nous avons:
protocol P {}
extension P {
static var foo: Int {
return 5
}
static let bar = "" // error: Static stored properties not supported in generic types
// (not really a great diagnostic)
}
struct S : P {}
struct S1 : P {}
Nous ne pouvons pas accéder à foo
sur le type de protocole lui-même, nous ne pouvons pas dire P.foo
. Nous pouvons seulement dire S.foo
ou S1.foo
. Ceci est important car le getter de foo
peut appeler des exigences de protocole statiques sur self
; mais ce n'est pas possible si self
est P.self
(c'est-à-dire le type de protocole lui-même), comme les protocoles ne sont pas conformes à eux-mêmes .
Il en irait (probablement) de même pour les propriétés stockées static
telles que bar
.
class
Je ne pense pas qu'il y aurait des problèmes avec une telle déclaration dans le corps de classe lui-même (elle serait simplement équivalente à une propriété class
calculée et soutenue par une propriété stockée static
).
Cependant, cela le serait pourrait être problématique dans les extensions, car les extensions ne peuvent pas ajouter de nouveaux membres à une table de classe Swift (bien qu'elles puissent ajouter à l'homologue Obj-C si Par conséquent, dans la plupart des cas, ils ne seraient pas distribués de manière dynamique vers (ainsi serait effectivement final
, et donc static
). Bien que cela étant dit, class
computed les propriétés sont actuellement autorisées dans les extensions, donc cela peut être autorisé dans un souci de cohérence.