Statische Funktionsvariablen in Swift

96

Ich versuche herauszufinden, wie eine statische Variable deklariert wird, die nur lokal für eine Funktion in Swift gültig ist.

In C könnte dies ungefähr so ​​aussehen:

int foo() {
    static int timesCalled = 0;
    ++timesCalled;
    return timesCalled;
}

In Objective-C ist es im Grunde dasselbe:

- (NSInteger)foo {
    static NSInteger timesCalled = 0;
    ++timesCalled;
    return timesCalled;
}

Aber ich kann so etwas in Swift scheinbar nicht machen. Ich habe versucht, die Variable folgendermaßen zu deklarieren:

static var timesCalledA = 0
var static timesCalledB = 0
var timesCalledC: static Int = 0
var timesCalledD: Int static = 0

Dies alles führt jedoch zu Fehlern.

  • Die erste Beschwerde "Statische Eigenschaften dürfen nur für einen Typ deklariert werden".
  • Der zweite beschwert sich über "Erwartete Deklaration" (wo staticist) und "Erwartetes Muster" (wo timesCalledBist)
  • Der dritte beschwert sich über "Aufeinanderfolgende Anweisungen in einer Zeile müssen durch ';'" (im Leerzeichen zwischen Doppelpunkt und static) und "Erwarteter Typ" (wo staticist) getrennt werden.
  • Die vierte Beschwerde lautet "Aufeinanderfolgende Anweisungen in einer Zeile müssen durch ';'" (im Leerzeichen zwischen Intund static) und "Erwartete Deklaration" (unter dem Gleichheitszeichen) getrennt werden.
nhgrif
quelle

Antworten:

158

Ich glaube nicht, dass Swift statische Variablen unterstützt, ohne sie an eine Klasse / Struktur anzuhängen. Versuchen Sie, eine private Struktur mit einer statischen Variablen zu deklarieren.

func foo() -> Int {
    struct Holder {
        static var timesCalled = 0
    }
    Holder.timesCalled += 1
    return Holder.timesCalled
}

  7> foo()
$R0: Int = 1
  8> foo()
$R1: Int = 2
  9> foo()
$R2: Int = 3
Bryan Chen
quelle
Ja, ich habe ein bisschen weitergespielt und das war im Grunde die wirklich klobige Lösung, die ich mir auch ausgedacht habe.
nhgrif
17
Upwoted, aber ich bin traurig, dass wir darauf zurückgreifen müssen.
Tricertops
1
Typeneigenschaften und -methoden gehören zu einem Typ (dh einer Klasse, Struktur oder Aufzählung) und können nicht allein zu einer Funktion gehören. Apple-Dokumentation zu Typeneigenschaften . @Tricertops. Eine andere Möglichkeit besteht darin, die Funktion "foo" in eine Klasse einzufügen, eine Typeigenschaft für diese Klasse zu erstellen und sie innerhalb der Funktion zu verwenden.
NSCoder
6
@NSCoder Es ist jedoch möglich, struct Holder {…}innerhalb mehrerer Funktionen zu deklarieren, und sie kollidieren nicht. Swift könnte static letohne diese structBoilerplate herum unterstützen.
Tricertops
1
@Honey Es tut mir leid, aber ich kann keine aktualisierte andere Antwort finden?
Bryan Chen
23

Eine andere Lösung

func makeIncrementerClosure() -> () -> Int {
    var timesCalled = 0
    func incrementer() -> Int {
        timesCalled += 1
        return timesCalled
    }
    return incrementer
}

let foo = makeIncrementerClosure()
foo()  // returns 1
foo()  // returns 2
Monadis
quelle
3
Dies ist eine typische Javascript-Methode
Bryan Chen
1
Wenn ich aber wieder ba () aufrufe, gibt die innere Funktion beim ersten Aufruf 1 zurück. Dies unterscheidet sich von einer statischen Variablen.
nhgrif
2
Dies wird auch in Apples Dokumenten hier gelehrt: developer.apple.com/library/ios/documentation/Swift/Conceptual/… Es scheint die beste Lösung zu sein, nur um mit der "funktionalen Programmierung" Schritt zu halten, aber es gibt auch andere Lösungen als Gut. Dies sollte jedoch die akzeptierte Antwort sein.
datWooWoo
1
Es tut mir leid, aber dies ist ein hässlicher Hack, der das gleiche Problem komplexer macht. Worauf willst du hinaus? In diesem Fall bevorzuge ich eine einfache Klasseneigenschaft. @ Brian Chens Antwort ist die nächstgelegene, die Sie bekommen können. Ich benutze seine Antwort für eine Flipflop-Lösung. Daniel entspricht vielleicht am besten den Apple-Regeln für die Swift-Programmierung.
Andalus
1
Diese Lösung hat mir besonders gut gefallen. Dies ist ein perfektes Beispiel für die Verwendung einer Funktion höherer Ordnung, um das gleiche Ergebnis wie eine statische Variable innerhalb des Funktionsumfangs zu erzielen. Statische Funktionsvariablen werden in Swift aus guten Gründen nicht nativ unterstützt. Es ist die natürliche Entwicklung der Programmierung. Der Versuch, auf altmodische Weise zu codieren, erfordert Hacks. Meiner Meinung nach verringert das Hinzufügen eines zusätzlichen verschachtelten Datentyps im Gegensatz zur Verwendung der Variablenerfassung die Lesbarkeit des Codes.
Nstein
18

Swift 1.2 mit Xcode 6.3 unterstützt jetzt wie erwartet statisch. Aus den Versionshinweisen zur Beta-Version von Xcode 6.3:

"Statische" Methoden und Eigenschaften sind jetzt in Klassen zulässig (als Alias ​​für "class final"). Sie können jetzt statisch gespeicherte Eigenschaften in Klassen deklarieren, die über globalen Speicher verfügen und beim ersten Zugriff träge initialisiert werden (wie globale Variablen). Protokolle deklarieren jetzt Typanforderungen als "statische" Anforderungen, anstatt sie als "Klassen" -Anforderungen zu deklarieren. (17198298)

Es scheint, dass Funktionen keine statischen Deklarationen enthalten können (wie in Frage gestellt). Stattdessen muss die Deklaration auf Klassenebene erfolgen.

Einfaches Beispiel für eine statische Eigenschaft, die innerhalb einer Klassenfunktion (auch als statische Funktion bezeichnet) inkrementiert wurde, obwohl eine Klassenfunktion nicht erforderlich ist:

class StaticThing
{
    static var timesCalled = 0

    class func doSomething()
    {
        timesCalled++

        println(timesCalled)
    }
}

StaticThing.doSomething()
StaticThing.doSomething()
StaticThing.doSomething()

Ausgabe:

1
2
3
Daniel
quelle
1
Ich vermute, dass dieser Unterschied in der Bedeutung von staticApple beabsichtigt sein könnte, obwohl man immer gerne einen Fehler einreichen kann , um eine Änderung anzufordern. In C wird staticdie Speicherung einer Variablen auf den Bereich der Quelldatei beschränkt (was nicht immer mit dem Klassenbereich identisch ist), während die Platzierung der Variablendeklaration den lexikalischen Bereich bestimmt (dh global vs innerhalb der Funktion vs viele verschachtelte {}s). In Swift folgt der Speicherbereich immer dem lexikalischen Bereich, sodass Sie keine Variable haben können, die für eine Funktion lexikalisch ist und über globalen Speicher verfügt.
Rickster
5
Daniel, das unterscheidet sich tatsächlich subtil (aber wichtig) von dem, was die Frage stellt. Ich schätze die Antwort. @rickster Ich verstehe, was Sie sagen und denke, Ihr Kommentar könnte zu einer guten Antwort auf diese Frage erweitert werden.
nhgrif
@nhgrif Ja, ich habe in der Antwort angegeben, dass dies nicht die spezifische Frage anspricht. Ich dachte nur, dass die Änderungen in Swift 1.2 den Kernbedarf für diesen Anwendungsfall decken (sicherlich eine bessere Geschichte als vor Swift 1.2). Es scheint jedoch wichtig zu sein, dass Sie einen variablen Bereich für die Funktion haben - was derzeit nicht möglich ist.
Daniel
@rickster in CI denken, dass statisch immer global gespeichert wird. Ich bin mir aber nicht sicher. Ich denke, das ist das Problem, das Apple hier zu lösen versucht. In Kürze ist es jetzt immer lexikalisch und speicherbezogen für die Klasse
BTRUE
@nhgrif Mit meinem vorherigen Kommentar denke ich, dass Daniels Antwort eigentlich die akzeptierte Antwort sein sollte, denn obwohl Sie eine statische Variable in einer Funktion in objc lexikalisch deklarieren können, wurde sie dort nicht festgelegt und hat den gleichen Effekt wie die Verwendung eines statischen Typs Eigentum in schnell. Der einzige Unterschied besteht darin, dass der schnelle Deklarationspunkt viel aussagekräftiger und nicht irreführend ist, was den Umfang der Variablen betrifft.
BTRUE
0

Eine andere Lösung

class Myclass {
    static var timesCalled = 0
    func foo() -> Int {
        Myclass.timesCalled += 1
        return Myclass.timesCalled
    }
}
Jq
quelle