Статичні змінні функції в Swift


96

Я намагаюся зрозуміти, як оголосити статичну змінну, локалізовану лише локально, до функції в 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) та "Очікувана декларація" (під знаком рівності)

Відповіді:


158

Я не думаю, що 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

Так, я продовжив трохи гратись, і це було в основному справді незграбне рішення, яке я також придумав.
nhgrif

17
Засмучений, але мені сумно, що ми маємо вдатися до цього.
Tricertops

1
Властивості та методи типу належать до типу (тобто класу, структури або переліку) і не можуть належати лише функції. Документація Apple щодо властивостей типу . @Tricertops. Інший спосіб зробити це - помістити функцію "foo" у клас, створити властивість type для цього класу та використовувати її всередині функції.
NSCoder 02.03.16

6
@NSCoder Але можна оголосити struct Holder {…}всередині декількох функцій, і вони не зіткнуться. Свіфт міг би підтримати static letбез цього structшаблону.
Tricertops

1
@Honey Вибачте, але я не можу знайти більш оновлену іншу відповідь?
Bryan Chen

23

Ще одне рішення

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
це типовий спосіб JavaScript
Брайан Чен,

1
Але якщо я знову викликаю ba (), внутрішня функція повертає 1 при першому виклику. Це відрізняється від статичної змінної.
nhgrif

2
Це також викладається в документах Apple тут: developer.apple.com/library/ios/documentation/Swift/Conceptual/... Здається, це найкраще рішення просто дотримуватися «функціонального програмування», але є й інші рішення, як Ну. Однак це має бути прийнятою відповіддю.
datWooWoo

1
Вибачте, але це потворний хак, який додає більшої складності для тієї ж проблеми. Який ваш сенс? У цьому випадку я віддаю перевагу простому властивості класу. Відповідь @Brian Chen - це найближча відповідь, яку ви можете отримати. Я використовую його відповідь для вирішення проблеми. Деніел, мабуть, найкраще відповідає правилам Apple щодо швидкого програмування.
AndaluZ,

1
Мені особливо сподобалось це рішення. Це чудовий приклад використання функції вищого порядку для досягнення того самого результату, що і статична змінна всередині області дії функції. Статичні функції функцій не підтримуються в Swift з поважних причин. Це природна еволюція програмування. Спроба кодування за старими способами вимагає хакерів. На мій погляд, додавання додаткового вкладеного типу даних, на відміну від використання змінних, зменшує читабельність коду.
nstein

18

Swift 1.2 з Xcode 6.3 тепер підтримує статичну, як очікувалося. З приміток про бета-версію Xcode 6.3:

«Статичні» методи та властивості тепер дозволені в класах (як псевдонім для «final final»). Тепер вам дозволено оголошувати статичні збережені властивості в класах, які мають глобальне сховище та ліниво ініціалізуються при першому доступі (як глобальні змінні). Протоколи тепер оголошують вимоги до типу як “статичні” вимоги замість того, щоб оголошувати їх як вимоги “класу”. (17198298)

Здається, функції не можуть містити статичні декларації (як про це йдеться). Натомість оголошення потрібно робити на рівні класу.

Простий приклад, що показує статичну властивість, збільшену всередині функції класу (вона ж статична), хоча функція класу не потрібна:

class StaticThing
{
    static var timesCalled = 0

    class func doSomething()
    {
        timesCalled++

        println(timesCalled)
    }
}

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

Вихід:

1
2
3

1
Я підозрюю, що ця різниця у значенні staticможе бути навмисною з боку Apple, хоча завжди можна запросити помилку, щоб вимагати змін. У C staticобмежує зберігання змінної до обсягу вихідного файлу (що не завжди збігається з обсягом класу), тоді як розміщення оголошення змінної визначає лексичний обсяг (тобто глобальний проти в межах функції проти багато вкладених {}). У Swift обсяг зберігання завжди слідує за лексичним обсягом, тому ви не можете мати змінну, яка є лексичною для функції та має глобальне сховище.
рикстер

5
Даніелю, це насправді дещо (але важливо) відрізняється від того, що задає питання. Я ціную відповідь. @rickster Я розумію, що ви говорите, і думаю, що ваш коментар може бути розширений до хорошої відповіді на це питання.
nhgrif

@nhgrif Так, я відповів у відповіді, що це не стосується конкретного питання. Я просто думав, що зміни в Swift 1.2 стосуються основної потреби у цьому випадку використання (безумовно, краща історія, ніж до Swift 1.2). Але, схоже, для вас важливо встановити масштаб змінної функції - що наразі неможливо.
Даніель

@rickster у CI вважає, що статичне завжди зберігається глобально насправді. Але я не впевнений. Я думаю, що це проблема, яку Apple намагається вирішити тут. Швидко, тепер це завжди лексично та обсяг пам’яті
припадає

@nhgrif З моїм попереднім коментарем, я думаю, що відповідь Даніеля насправді повинна бути прийнятою відповіддю, тому що, хоча ви можете лексично оголосити статичний var у функції в objc, він не був застосований там, маючи такий же ефект, як використання статичного типу власність швидко. єдина відмінність полягає в тому, що точка швидкого оголошення набагато описовіша і не вводить в оману щодо того, якою є сфера дії змінної.
BTRUE

0

Ще одне рішення

class Myclass {
    static var timesCalled = 0
    func foo() -> Int {
        Myclass.timesCalled += 1
        return Myclass.timesCalled
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.