函数中的Swift常量(带计算)?

Fat*_*tie 5 static swift computed-properties

这是一个简单的Swift函数

fileprivate func test()->String{
    let c = Array("abc".characters)
    let k = UInt32(c.count)
    let r = Int(arc4random_uniform(k))
    return String(c[r])
}
Run Code Online (Sandbox Code Playgroud)

(我选择这个例子是因为很明显,你可能会调用数十亿次来生成某种输出;所以你可能会担心设置两个常量的性能.)

请注意,它必须进行一些计算才能获得c,并且确实k需要使用它c.

我的问题很简单:每次调用此函数

test()
test()
test()
Run Code Online (Sandbox Code Playgroud)

实际上它是在计算k,和/或c 每次调用它,或者它们实际上只计算一次

(如果"只有一次",那么作为一个好奇心:它是第一次调用函数时这样做?或者编译器可能会在启动时单独完成它?或者就此而言它是否知道它可以在编译期间计算它们?)


我经常使用全局计算属性,就像这样

let basicDF : DateFormatter = {
    print("this will only be done once per launch of the app")
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd"
    return formatter 
}()
Run Code Online (Sandbox Code Playgroud)

(也许有fileprivate)如果上面问题的答案是"no,c并且每次调用test时计算'k',那么在这种情况下如何在函数中放置一种静态计算属性?

Ham*_*ish 4

不,在您的特定情况下,编译器当前不会优化c和/或k只计算一次的常量表达式(这可以通过检查 IR看出)检查优化构建中的看出)\xe2\x80\x93 尽管这就是全部可能会随着该语言的未来版本而变化。

\n\n

但值得注意的是,它目前可以对更简单的表达式执行此操作,例如:

\n\n
func foo() -> Int {\n    return 2 + 4\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

编译器可以在编译时评估加法,因此该函数只是执行return 6(然后可以内联)。但当然,如果您实际上已将给定函数确定为性能瓶颈,那么您首先应该担心此类优化。

\n\n

在函数中获取静态常量的一个好技巧是定义一个无大小写的enum在函数中获取静态常量的一个好技巧是在函数作用域中

\n\n
func test() -> String {\n\n    enum Constants {\n        static let c = Array("abc".characters)\n        static let k = UInt32(c.count)\n    }\n\n    let r = Int(arc4random_uniform(Constants.k))\n    return String(Constants.c[r])\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

c现在和的初始化表达式k只会被计算一次,并且这将在第一次使用它们时(即第一次调用函数时)完成。

\n\n

当然,正如您所展示的,您可以使用立即计算的闭包以获得多行初始化表达式:

\n\n
enum Constants {\n    static let c: [Character] = {\n        // ...\n        return Array("abc".characters)\n    }()\n    // ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n