Swift'deki statik fonksiyon değişkenleri


97

Swift'deki bir işleve yalnızca yerel olarak kapsamlı bir statik değişkeni nasıl bildireceğimi anlamaya çalışıyorum.

C'de, bu şunun gibi görünebilir:

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

Objective-C'de, temelde aynı:

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

Ama Swift'de böyle bir şey yapamıyorum. Değişkeni aşağıdaki şekillerde açıklamayı denedim:

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

Ancak bunların hepsi hatalarla sonuçlanır.

  • İlk şikayet "Statik özellikler yalnızca bir tür üzerinde bildirilebilir".
  • İkinci şikayet "Beklenen beyan" (nerede static) ve "Beklenen model" (nerede timesCalledB)
  • Üçüncü şikayet "Bir satırdaki ardışık ifadeler ';'" (iki nokta üst üste ile arasındaki boşlukta static) ve "Beklenen Tür" (nerede static) ile ayrılmalıdır.
  • Dördüncü " ';' ile ayrılmalıdır bir satırda Ardıl ifadeleri" şikayet (arasındaki boşlukta Intve static(eşittir işareti altında)) ve "Beklenen beyanı"

Yanıtlar:


159

Swift'in statik değişkeni bir sınıfa / yapıya eklenmeden desteklediğini sanmıyorum. Statik değişkenli özel bir yapı bildirmeyi deneyin.

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

Evet, biraz oynamaya devam ettim ve bu temelde bulduğum gerçekten hantal çözümdü.
nhgrif

17
Sinirliyim ama buna başvurmak zorunda olduğumuz için üzgünüm.
Tricertops

1
Tür özellikleri ve yöntemleri bir türe (örneğin, Sınıf, Yapı veya Enum) aittir ve tek başına bir işleve ait olamaz. Tür Özelliklerine İlişkin Apple Belgeleri . @Fotomac Bunu yapmanın başka bir yolu da "foo" işlevini bir sınıfa koymak, bu sınıf için bir tür özelliği oluşturmak ve bunu işlev içinde kullanmaktır.
NSCoder

6
@NSCoder Ancak struct Holder {…}birden fazla işlevin içinde beyan etmek mümkündür ve bunlar çakışmazlar . Swift, static letbu structşablon olmadan destekleyebilirdi .
Tricertops

1
@Honey Üzgünüm ama daha güncel başka cevap bulamıyorum?
Bryan Chen

23

Başka bir çözüm

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
bu, bunu yapmanın tipik bir javascript yolu
Bryan Chen

1
Fakat ba () 'yı tekrar çağırırsam, iç işlev ilk çağrıda 1 döndürür. Bu, statik bir değişkenden farklıdır.
nhgrif

2
Bu, Apple'ın buradaki belgelerinde de öğretilmektedir: developer.apple.com/library/ios/documentation/Swift/Conceptual/… Sadece "işlevsel programlama" ile aynı çizgide kalmak için en iyi çözüm gibi görünüyor, ancak başka çözümler de var. iyi. Yine de kabul edilen cevap bu olmalıdır.
datWooWoo

1
Üzgünüm, ama bu aynı soruna daha fazla karmaşıklık katan çirkin bir hack. Ne demek istiyorsun? Bu durumda basit bir sınıf özelliğini tercih ederim. @ Brian Chen'in cevabı, alabileceğiniz en yakın cevaptır. Cevabını iki duraklı bir çözüm için kullanıyorum. Daniel belki de Apple'ın Swift programlama kurallarına en uygun olanıdır.
AndaluZ

1
Bu çözümü özellikle beğendim. Bu, bir işlevin kapsamı içindeki statik bir değişkenle aynı sonucu elde etmek için daha yüksek dereceli bir işlevi kullanmanın mükemmel bir örneğidir. Statik işlev değişkenleri, iyi nedenlerden ötürü Swift'de yerel olarak desteklenmemektedir. Programlamanın doğal evrimi. Eski moda yöntemlerle kodlamaya çalışmak, kesmek gerektirir. Benim düşünceme göre, değişken yakalama yerine fazladan yuvalanmış bir veri türü eklemek kod okunabilirliğini azaltır.
nstein

18

Xcode 6.3 ile Swift 1.2 artık beklendiği gibi statik desteği sağlıyor. Xcode 6.3 beta sürüm notlarından:

Artık sınıflarda "statik" yöntemlere ve özelliklere izin verilmektedir ("sınıf finali" için bir takma ad olarak). Artık, genel depolamaya sahip olan ve ilk erişimde (genel değişkenler gibi) tembel olarak başlatılan sınıflarda statik depolanan özellikleri bildirmenize izin verilmektedir. Protokoller artık tür gereksinimlerini "sınıf" gereksinimleri olarak bildirmek yerine "statik" gereksinimler olarak bildirmektedir. (17198298)

Görünüşe göre işlevler statik bildirimler içeremez (soruda sorulduğu gibi). Bunun yerine, beyan sınıf düzeyinde yapılmalıdır.

Bir sınıf işlevi gerekmese de, bir sınıf (aka statik) işlevi içinde artırılmış statik bir özelliği gösteren basit örnek:

class StaticThing
{
    static var timesCalled = 0

    class func doSomething()
    {
        timesCalled++

        println(timesCalled)
    }
}

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

Çıktı:

1
2
3

1
Bunun anlamındaki bu farkın staticApple'ın kasıtlı olabileceğinden şüpheleniyorum , ancak bir değişiklik talep etmek için her zaman bir hata başvurusunda bulunulabilir . C'de, bir değişkenin depolanmasını kaynak dosya kapsamıyla staticsınırlandırırken (bu her zaman sınıf kapsamı ile aynı değildir), değişken bildiriminin yerleştirilmesi sözlü kapsamı belirler (yani, işlev içinde ve çok sayıda iç içe geçmişler ). Swift'de, depolama kapsamı her zaman sözlü kapsamı izler, bu nedenle bir işleve ilişkin sözlü ve genel depolamaya sahip bir değişkeniniz olamaz. {}
rickster

5
Daniel, bu aslında sorunun sorduğundan çok ince (ama önemli ölçüde) farklı. Yine de cevabı takdir ediyorum. @rickster Ne söylediğinizi anlıyorum ve yorumunuzun bu soru için iyi bir cevaba genişletilebileceğini düşünüyorum.
nhgrif

@nhgrif Evet, cevabımda bunun belirli bir soruyu ele almadığını belirttim. Swift 1.2'deki değişikliklerin bu kullanım senaryosuna yönelik temel ihtiyacı karşıladığını düşünüyordum (kesinlikle Swift 1.2 öncesinden daha iyi bir hikaye). Ancak, işlev için değişken kapsamına sahip olmanız sizin için önemli gibi görünüyor - bu şu anda mümkün değil.
Daniel

@rickster in C Bence statik her zaman küresel olarak depolanıyor. Yine de emin değilim. Sanırım Apple'ın burada ele almaya çalıştığı sorun bu. Hızlı olarak, artık her zaman sözcüksel olarak ve depolama alanı sınıfına göre
ayarlanmıştır

@nhgrif Önceki yorumumda söylediğim gibi, Daniel'in cevabının aslında kabul edilen cevap olması gerektiğini düşünüyorum, çünkü objc'deki bir fonksiyonda sözcüksel olarak statik bir var bildirebilseniz de, orada kapsamlı değildi, statik Tip kullanmakla aynı etkiye sahipti hızlı mülk. tek fark, hızlı bildirim noktasının çok daha açıklayıcı olması ve değişkenin kapsamının ne olduğu konusunda yanıltıcı olmamasıdır.
BTRUE

0

Başka bir çözüm

class Myclass {
    static var timesCalled = 0
    func foo() -> Int {
        Myclass.timesCalled += 1
        return Myclass.timesCalled
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.