Swift中的静态函数变量


96

我试图弄清楚如何声明一个静态变量,其作用域仅限于Swift中的函数。

在C中,这可能看起来像这样:

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

在Objective-C中,基本上是相同的:

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

但是我似乎无法在Swift中做类似的事情。我尝试通过以下方式声明变量:

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

但是这些都会导致错误。

  • 第一个抱怨“静态属性只能在类型上声明”。
  • 第二个抱怨“期望的声明”(在哪里static)和“期望的模式”(在哪里timesCalledB
  • 第三条抱怨“一行上的连续语句必须用';'分隔(在冒号和之间的空格static)和” Expected Type”(在哪里static
  • 第四抱怨“上一个线必须被分开连续语句‘;’”(在之间的空间Intstatic)和“预期声明”(下等号)

Answers:


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 2014年

17
赞不绝口,但我很抱歉我们不得不诉诸这一点。
Tricertops

1
类型属性和方法属于类型(即,Class,Struct或Enum),不能单独属于函数。Apple有关类型属性的文档。@Tricertops。解决此问题的另一种方法是将函数“ foo”放在一个类中,为该类创建一个type属性,然后在函数内部使用它。
NSCoder

6
@NSCoder但是可以struct Holder {…}在多个函数中声明,它们不会冲突。Swift可以在static let没有这种struct样板的情况下提供支持。
Tricertops

1
@Honey对不起,我找不到更多更新的其他答案?
布赖恩·陈

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 2014年

2
这在苹果文档中也有讲解:developer.apple.com/library/ios/documentation/Swift/Conceptual/… 似乎与“函数式编程”保持一致是最好的解决方案,但是还有其他解决方案好。不过,这应该是公认的答案。
datWooWoo

1
抱歉,这是一个丑陋的hack,它为同一问题增加了更多的复杂性。你想说什么?在那种情况下,我更喜欢一个简单的类属性。@Brian Chen的答案是最接近的答案。我用他的答案作为触发器的一种解决方案。Daniel可能是最符合Apple的Swift编程规则的人。
AndaluZ 2015年

1
我特别喜欢这个解决方案。这是使用高阶函数来实现与函数范围内的静态变量相同的结果的完美示例。出于充分的理由,Swift本身不支持静态函数var。这是编程的自然演变。尝试以旧的方式进行编码需要黑客。我认为,与利用变量捕获相反,添加额外的嵌套数据类型会降低代码的可读性。
nstein 2016年

18

带有Xcode 6.3的Swift 1.2现在支持预期的静态功能。从Xcode 6.3 beta发行说明中:

现在在类中允许使用“静态”方法和属性(作为“最终类”的别名)。现在,您可以在类中声明静态存储的属性,这些类具有全局存储,并在首次访问时被延迟初始化(如全局变量)。协议现在将类型要求声明为“静态”要求,而不是将其声明为“类”要求。(17198298)

看来函数不能包含静态声明(如所问的那样)。相反,声明必须在类级别完成。

一个简单的示例,显示一个静态属性在类(又称静态)函数中递增,尽管不需要类函数:

class StaticThing
{
    static var timesCalled = 0

    class func doSomething()
    {
        timesCalled++

        println(timesCalled)
    }
}

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

输出:

1
2
3

1
我怀疑这种意义上的差异static可能是苹果公司故意制造的,尽管总是欢迎人们提出错误要求更改。在C语言中,static将变量的存储范围限制为源文件范围(并不总是与类范围相同),而变量声明的位置确定词法范围(即,全局vs函数内部vs多嵌套{})。在Swift中,存储作用域始终遵循词法作用域,因此您不能拥有对函数而言词法化且具有全局存储的变量。
rickster 2015年

5
丹尼尔(Daniel),这实际上是(但重要地)与问题所要的内容有所不同。我很感谢答案。@rickster我理解您在说什么,并认为您的评论可以扩展为该问题的一个很好的答案。
nhgrif 2015年

@nhgrif是的,我在回答中指出这没有解决特定的问题。我只是在想,Swift 1.2中的更改满足了此用例的核心需求(肯定比Swift 1.2之前的版本更好)。但是,将变量的作用域范围限定为函数似乎很重要-目前这是不可能的。
丹尼尔(Daniel)

CI中的@rickster认为static总是实际实际存储在全局中。我不确定。我认为这就是Apple试图解决的问题。迅速地,它现在总是按词法分类,并且存储范围
仅限

@nhgrif用我之前的评论说,我认为Daniel的答案实际上应该是被接受的答案,因为尽管您可以在objc中的函数中用词法声明一个静态var,但它的作用域并不在那里,其作用与使用静态Type相同。财产迅速。唯一的区别是,快捷的声明点更具描述性,并且在变量的作用域方面没有误导。
BTRUE

0

另一种解决方案

class Myclass {
    static var timesCalled = 0
    func foo() -> Int {
        Myclass.timesCalled += 1
        return Myclass.timesCalled
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.