Статические функциональные переменные в Swift

Я пытаюсь выяснить, как объявить статическую переменную, локально привязанную к функции в Swift.

В C это может выглядеть примерно так:

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

В Objective-C он в основном тот же:

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

Но я не могу ничего подобного сделать в Свифте. Я попытался объявить переменную следующими способами:

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

Но все это приводит к ошибкам.

  • Первый жалуется: "Статические свойства могут быть объявлены только для типа".
  • Второй жалуется на "Ожидаемое объявление" (где static есть) и "Ожидаемый шаблон" (где timesCalledB)
  • Третий жалуется: "Последовательные операторы на строке должны быть разделены"; "(в пробеле между двоеточием и static) и" Ожидаемый тип "(где static)
  • Четвертый жалуется: "Последовательные операторы на строке должны быть разделены"; "(в промежутке между Int и static) и" Ожидаемое объявление "(под знаком равенства)

Ответ 1

Я не думаю, что Swift поддерживает статическую переменную без привязки к классу/структуре. Попробуйте объявить частную структуру со статической переменной.

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

Ответ 2

Другое решение

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

let foo = makeIncrementerClosure()
foo()  // returns 1
foo()  // returns 2

Ответ 3

Swift 1.2 с Xcode 6.3 теперь поддерживает статические как ожидалось. Из примечаний к выпуску Xcode 6.3:

"статические" методы и свойства теперь разрешены в классах (как псевдоним для "final class" ). Теперь вам разрешено объявлять статические данные свойства в классах, которые имеют глобальное хранилище и ленивы инициализируется при первом доступе (например, глобальные переменные). Протоколы сейчас объявлять требования типа как "статические" требования вместо заявляя их как "классные" требования. (17198298)

Похоже, что функции не могут содержать статические объявления (как задано в вопросе). Вместо этого объявление должно выполняться на уровне класса.

Простой пример, показывающий статическое свойство, добавленное внутри функции класса (aka static), хотя функция класса не требуется:

class StaticThing
{
    static var timesCalled = 0

    class func doSomething()
    {
        timesCalled++

        println(timesCalled)
    }
}

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

Вывод:

1
2
3