Variabel fungsi statis di Swift

96

Saya mencoba mencari cara untuk mendeklarasikan variabel statis yang hanya dibatasi secara lokal ke fungsi di Swift.

Di C, ini mungkin terlihat seperti ini:

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

Di Objective-C, pada dasarnya sama:

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

Tapi sepertinya saya tidak bisa melakukan hal seperti ini di Swift. Saya sudah mencoba mendeklarasikan variabel dengan cara berikut:

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

Tapi ini semua menghasilkan kesalahan.

  • Keluhan pertama "Properti statis hanya dapat dideklarasikan pada jenis".
  • Keluhan kedua "Deklarasi yang diharapkan" (di mana static) dan "Pola yang diharapkan" (di mana timesCalledB)
  • Keluhan ketiga "Pernyataan berurutan pada sebuah baris harus dipisahkan oleh ';'" (dalam spasi antara titik dua dan static) dan "Jenis yang Diharapkan" (di mana static)
  • Keluhan keempat "Pernyataan berturut-turut pada sebuah baris harus dipisahkan oleh ';'" (di antara Intdan static) dan "Deklarasi yang diharapkan" (di bawah tanda sama dengan)
nhgrif
sumber

Jawaban:

158

Saya tidak berpikir Swift mendukung variabel statis tanpa dilampirkan ke kelas / struct. Coba deklarasikan struct pribadi dengan variabel statis.

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
sumber
Ya, saya terus bermain-main sedikit dan ini pada dasarnya adalah solusi yang sangat kikuk yang saya temukan juga.
nhgrif
17
Upwoted, tapi saya sedih kita harus resor ini.
Tricertops
1
Jenis properti dan metode milik suatu jenis (yaitu Kelas, Struktur atau Enum) dan tidak bisa menjadi milik fungsi sendiri. Dokumentasi Apple tentang Properti Jenis . @Tokopedia Cara lain untuk melakukannya adalah dengan meletakkan fungsi "foo" di kelas, membuat properti tipe untuk kelas itu dan menggunakannya di dalam fungsi.
NSCoder
6
@NSCoder Tapi itu mungkin untuk mendeklarasikan struct Holder {…}di dalam beberapa fungsi dan mereka tidak akan bertabrakan. Swift dapat mendukung static lettanpa structboilerplate ini .
Tricertops
1
@Honey Saya minta maaf, tetapi saya tidak dapat menemukan jawaban lain yang lebih diperbarui?
Bryan Chen
23

Solusi lain

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
sumber
3
ini adalah cara javascript tipikal untuk melakukannya
Bryan Chen
1
Tetapi jika saya memanggil ba () lagi, fungsi bagian dalam mengembalikan 1 pada panggilan pertama. Ini berbeda dari variabel statis.
nhgrif
2
Hal ini juga diajarkan dalam dokumen Apple di sini: developer.apple.com/library/ios/documentation/Swift/Conceptual/… Tampaknya menjadi solusi terbaik hanya untuk tetap sejalan dengan "pemrograman fungsional", tetapi ada solusi lain sebagai baik. Ini harus menjadi jawaban yang diterima.
datWooWoo
1
Maaf, tapi ini adalah peretasan jelek yang menambahkan lebih banyak kerumitan untuk masalah yang sama. Apa maksudmu? Dalam hal ini saya lebih suka properti kelas sederhana. Jawaban @ Brian Chen adalah yang paling dekat yang bisa Anda dapatkan. Saya menggunakan jawabannya untuk solusi jenis flipflop. Daniel mungkin yang paling sesuai dengan aturan Apple tentang pemrograman Swift.
AndaluZ
1
Saya sangat menyukai solusi ini. Ini adalah contoh sempurna menggunakan fungsi tingkat tinggi untuk mencapai hasil yang sama sebagai variabel statis di dalam cakupan suatu fungsi. Variabel fungsi statis tidak didukung secara native di Swift untuk alasan yang bagus. Itu adalah evolusi alami dari pemrograman. Mencoba membuat kode dengan cara lama membutuhkan peretasan. Menurut pendapat saya, menambahkan tipe data bersarang ekstra sebagai lawan menggunakan pengambilan variabel mengurangi keterbacaan kode.
nstein
18

Swift 1.2 dengan Xcode 6.3 sekarang mendukung statis seperti yang diharapkan. Dari catatan rilis Xcode 6.3 beta:

Metode dan properti "statis" sekarang diizinkan di kelas (sebagai alias untuk "kelas final"). Anda sekarang diizinkan untuk mendeklarasikan properti tersimpan statis di kelas, yang memiliki penyimpanan global dan dengan malas diinisialisasi pada akses pertama (seperti variabel global). Protokol sekarang mendeklarasikan persyaratan jenis sebagai persyaratan "statis" alih-alih mendeklarasikannya sebagai persyaratan "kelas". (17198298)

Tampaknya fungsi tidak dapat berisi deklarasi statis (seperti yang ditanyakan). Sebaliknya, deklarasi harus dilakukan di tingkat kelas.

Contoh sederhana yang menampilkan properti statis yang bertambah di dalam fungsi kelas (alias statis), meskipun fungsi kelas tidak diperlukan:

class StaticThing
{
    static var timesCalled = 0

    class func doSomething()
    {
        timesCalled++

        println(timesCalled)
    }
}

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

Keluaran:

1
2
3
Daniel
sumber
1
Saya menduga perbedaan dalam arti ini staticmungkin disengaja dari pihak Apple, meskipun seseorang selalu dapat melaporkan bug untuk meminta perubahan. Dalam C, staticmembatasi penyimpanan variabel ke lingkup file-sumber (yang tidak selalu sama dengan cakupan kelas), sedangkan penempatan deklarasi variabel menentukan cakupan leksikal (yaitu global vs dalam fungsi vs banyak-bersarang {}). Di Swift, cakupan penyimpanan selalu mengikuti cakupan leksikal, jadi Anda tidak bisa memiliki variabel yang leksikal ke suatu fungsi dan yang memiliki penyimpanan global.
rickster
5
Daniel, ini sebenarnya secara halus (tapi penting) berbeda dari pertanyaan yang diajukan. Saya menghargai jawabannya. @rickster Saya mengerti apa yang Anda katakan dan menurut saya komentar Anda dapat diperluas menjadi jawaban yang bagus untuk pertanyaan ini.
nhgrif
@nhgrif Ya, saya menunjukkan dalam jawaban bahwa ini tidak membahas pertanyaan spesifik. Saya baru saja berpikir bahwa perubahan di Swift 1.2 memenuhi kebutuhan inti untuk kasus penggunaan ini (tentu saja cerita yang lebih baik daripada sebelumnya Swift 1.2). Tapi sepertinya penting bagi Anda untuk memiliki variabel yang dicakup ke fungsi - yang saat ini tidak memungkinkan.
Daniel
@rickster di CI menganggap statis selalu disimpan secara global. Saya tidak yakin. Saya pikir itulah masalah yang coba diatasi Apple di sini. Dengan cepat, sekarang selalu secara leksikal dan penyimpanan
terbatas
@nhgrif Dengan komentar saya sebelumnya mengatakan, saya pikir jawaban Daniel sebenarnya harus menjadi jawaban yang diterima, karena meskipun Anda dapat secara leksikal mendeklarasikan var statis dalam fungsi di objc, itu tidak tercakup di sana, memiliki efek yang sama seperti menggunakan Jenis statis properti dengan cepat. satu-satunya perbedaan adalah, titik deklarasi swift jauh lebih deskriptif dan tidak menyesatkan seperti apa ruang lingkup variabel itu.
BTRUE
0

Solusi lain

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