L’estensione non può contenere proprietà archiviate, ma perché quindi la proprietà statica memorizzata può essere definita all’interno dell’estensione?
Inoltre, non ho trovato alcuna documentazione che menzionasse che la proprietà statica è consentita in estensione.
extension String { static let test = "Test" static var test2 = "Test2" }
Le estensioni non possono contenere proprietà di istanze memorizzate. Perché? Perché l’aggiunta di una proprietà di istanza cambierebbe la dimensione delle istanze di quel tipo. Cosa succede se un modulo aggiunge un’estensione tale che un Int
ora è lungo 2 parole? Cosa dovrebbe accadere quando, ad esempio, ottiene un Int
da un altro modulo dove hanno ancora 1 word in termini di dimensioni?
Il motivo per cui le proprietà statiche memorizzate sono permesse nelle estensioni è semplicemente perché hanno una durata statica; esistono indipendentemente dalle istanze del tipo specificato che stai estendendo. In realtà non sono nient’altro che variabili globali memorizzate, solo un namespace di un tipo. Pertanto possono essere aggiunti liberamente senza influenzare il codice che è già stato compilato senza la conoscenza di essi.
Vale la pena notare tuttavia che attualmente esistono tre restrizioni sulla definizione delle proprietà statiche memorizzate.
static
memorizzata su un tipo generico Ciò richiederebbe lo stoccaggio separato delle proprietà per ogni singola specializzazione dei segnaposti generici. Ad esempio, con:
struct S { static var foo: Int { return 5 } static let bar = "" // error: Static stored properties not supported in generic types }
Proprio come foo
viene chiamato sulla specializzazione individuale di S
, ad esempio S
e S
e non su S
stesso (infatti, S
non è nemmeno un tipo al momento, richiede che T
sia soddisfatto); bar
sarebbe (probabilmente) lo stesso. Sarebbe chiamato come, per esempio, S
, non S.bar
.
Questo è un dettaglio importante perché il metatipo su cui viene chiamato un membro statico viene passato al ricevitore come argomento implicito di self
. Questo è accessibile nelle espressioni di inizializzazione delle proprietà statiche; quindi permettendo loro di chiamare altri metodi statici.
Pertanto, essere in grado di chiamare lo stesso inizializzatore di proprietà statiche su specializzazioni differenti di un tipo generico potrebbe potenzialmente creare valori di proprietà diversi per ciascuno (si consideri il caso semplice di static let baz = T.self
). Pertanto abbiamo bisogno di una memoria separata per ciascuno di essi.
Tuttavia, detto tutto, non c’è una vera ragione per cui il compilatore / runtime non può farlo, e potrebbe benissimo farlo in una versione futura della lingua. Anche se un argomento contro questo è che in alcuni casi può produrre un comportamento confuso.
Ad esempio, considera:
import Foundation struct S { static let date = Date() }
Se il runtime generava implicitamente nuovo spazio di archiviazione per la date
ogni volta che si accede a una nuova specializzazione di S
, allora S
non sarebbe uguale a S
; che può essere fonte di confusione e / o indesiderabile.
static
memorizzata in un’estensione di protocollo Questo segue principalmente dal punto precedente. Una proprietà static
memorizzata in un’estensione di protocollo richiederebbe una memoria separata per ogni tipo conforms di quel protocollo (ma ancora una volta, non c’è motivo per cui il compilatore / runtime non possa farlo).
Ciò è necessario con i protocolli, poiché static
membri static
nelle estensioni di protocollo non sono membri del tipo di protocollo stesso. Sono membri di tipi concreti conformi al protocollo.
Ad esempio, se abbiamo:
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 {}
Non possiamo accedere a foo
sul tipo di protocollo stesso, non possiamo dire P.foo
. Possiamo solo dire S.foo
o S1.foo
. Questo è importante perché il getter di foo
può richiamare i requisiti del protocollo statico su self
; tuttavia ciò non è ansible se self
è P.self
(cioè il tipo di protocollo stesso ), poiché i protocolli non sono conformi a se stessi .
Lo stesso dovrebbe (probabilmente) seguire per static
proprietà static
memorizzate come la bar
.
class
Non credo che ci sarebbe alcun problema con una tale dichiarazione nel corpo della class stessa (sarebbe semplicemente equivalente a una proprietà di class
calcasting sostenuta da una proprietà static
immagazzinata).
Tuttavia, sarebbe potenzialmente problematico nelle estensioni, perché le estensioni non possono aggiungere nuovi membri a una class Swift vtable (sebbene possano aggiungersi alla controparte Obj-C, se applicabile). Pertanto nella maggior parte dei casi non sarebbero spediti dynamicmente (quindi sarebbe effettivamente final
, e quindi static
). Nonostante ciò, class
proprietà calcolate in class
sono attualmente consentite nelle estensioni, pertanto potrebbe essere consentita nell’interesse della coerenza.