【问题标题】:Static function variables in SwiftSwift 中的静态函数变量
【发布时间】:2014-10-10 20:51:46
【问题描述】:

我正在试图弄清楚如何在 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之间的空格中)和“预期类型”(static是)
  • 第四个抱怨“一行上的连续语句必须用';'分隔”(在Intstatic之间的空格中)和“预期声明”(在等号下)

【问题讨论】:

    标签: function static swift


    【解决方案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
    

    【讨论】:

    • 是的,我继续玩了一下,这基本上也是我想出的非常笨拙的解决方案。
    • Upwoted,但我很遗憾我们不得不求助于这个。
    • 类型属性和方法属于一个类型(即类、结构或枚举),不能单独属于一个函数。 Apple Documentation on Type Properties。 @Tricertops。另一种解决方法是将函数“foo”放入一个类中,为该类创建一个类型属性并在函数中使用它。
    • @NSCoder 但是可以在多个函数中声明struct Holder {…},它们不会发生冲突。没有这个 struct 样板,Swift 可以支持 static let
    • @Honey 对不起,我找不到更多更新的其他答案?
    【解决方案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
    

    【讨论】:

    • 这是一种典型的 javascript 方式
    • 但是如果我再次调用 ba(),内部函数在第一次调用时返回 1。这与静态变量不同。
    • 这在 Apple 的文档中也有介绍:developer.apple.com/library/ios/documentation/Swift/Conceptual/… 这似乎是与“函数式编程”保持一致的最佳解决方案,但也有其他解决方案。不过,这应该是公认的答案。
    • 我很抱歉,但这是一个丑陋的 hack,为同一问题增加了更多复杂性。你想说什么?在这种情况下,我更喜欢简单的类属性。 @Brian Chen 的答案是你能得到的最接近的答案。我将他的答案用于触发器类型的解决方案。 Daniel 可能是最符合 Apple Swift 编程规则的人。
    • 我特别喜欢这个解决方案。这是使用高阶函数在函数范围内实现与静态变量相同结果的完美示例。 Swift 本身不支持静态函数变量,这是有充分理由的。这是编程的自然演变。尝试以老式方式编写代码需要 hack。在我看来,添加额外的嵌套数据类型而不是使用变量捕获会降低代码的可读性。
    【解决方案3】:

    带有 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
    

    【讨论】:

    • 我怀疑static 含义上的这种差异可能是 Apple 有意为之,尽管我们始终欢迎 file a bug 请求更改。在 C 中,static 将变量的 storage 限制为源文件范围(并不总是与类范围相同),而变量声明的位置决定了 lexical i> 范围(即全局 vs 函数内 vs 多嵌套-{}s)。在 Swift 中,存储作用域始终遵循词法作用域,因此您不能拥有一个对函数来说是词法且具有全局存储空间的变量。
    • 丹尼尔,这实际上与问题所要求的略有不同(但重要的是)。我很感激这个答案。 @rickster 我明白你在说什么,并认为你的评论可以扩展为这个问题的一个很好的答案。
    • @nhgrif 是的,我在回答中指出这并没有解决具体问题。我只是在想 Swift 1.2 中的变化解决了这个用例的核心需求(当然比 Swift 1.2 之前的故事更好)。但听起来对你来说将变量范围限定为函数很重要——目前这是不可能的。
    • @rickster in C 我认为静态实际上总是全局存储的。不过我不确定。我认为这就是苹果试图在这里解决的问题。在 swift 中,它现在总是在词法上和存储范围为类
    • @nhgrif 我之前的评论说,我认为 Daniel 的答案实际上应该是公认的答案,因为虽然你可以在 objc 的函数中词法声明一个静态 var,但它并没有被限定在那里,有与在 swift 中使用静态 Type 属性的效果相同。唯一的区别是,swift 声明点更具描述性,不会误导变量的范围。
    【解决方案4】:

    另一种解决方案

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

    【讨论】:

      猜你喜欢
      • 2015-06-20
      • 1970-01-01
      • 2016-08-30
      • 1970-01-01
      • 2012-11-23
      • 1970-01-01
      • 2011-03-03
      • 2020-10-08
      相关资源
      最近更新 更多