web-dev-qa-db-fra.com

L'extension peut ne pas contenir de propriété stockée, mais pourquoi l'électricité statique est-elle autorisée

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"
}
18
Boon

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.

1. Vous ne pouvez pas définir une propriété stockée static sur un type générique

Cela 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.

2. Vous ne pouvez pas définir une propriété stockée static dans une extension de protocole

Cela 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.

3. Vous ne pouvez pas définir une propriété stockée 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, classcomputed les propriétés sont actuellement autorisées dans les extensions, donc cela peut être autorisé dans un souci de cohérence.

32
Hamish