2017-05-06 52 views
5

下面是一個簡單斯威夫特功能函數中的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]) 
} 

(我選擇了這個例子,因爲,很顯然,它的東西,你可以調用十億倍,產生某種輸出,所以你可能在設置兩個關注性能常量)。

請注意,它必須做一些計算才能得到c,並且確實得到k它必須使用c

我的問題很簡單:每次調用這個函數

test() 
test() 
test() 
其實

它計算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 
}() 

(也許fileprivate)如果回答上述問題是「沒有,c和數k '每次你都會計算c所有測試「,那麼在那種情況下,你怎麼能把一種靜態計算屬性放在函數內?

回答

3

不,你的具體情況,編譯器目前不優化c和/或k到只計算一次(這可以通過examining the IR在優化的建立可以看出)常量表達式 - 儘管這是所有受隨着未來版本的語言而改變。

然而,值得注意的是,它目前可以爲更簡單的表達式做到這一點,例如:

func foo() -> Int { 
    return 2 + 4 
} 

編譯器可以評估除了在編譯時間,所以功能少了點return 6(然後這可能是內聯)。但是,當然,如果您確實已經將給定的函數識別爲性能瓶頸,那麼您應該首先擔心這種優化。

一個很好的手段來得到靜態常量的功能是定義一個無外殼enum在功能範圍靜態屬性,在其中可以定義常量表達式:

func test() -> String { 

    enum Constants { 
     static let c = Array("abc".characters) 
     static let k = UInt32(c.count) 
    } 

    let r = Int(arc4random_uniform(Constants.k)) 
    return String(Constants.c[r]) 
} 

現在無論是初始化器ck的表達式只會被評估一次,並且這些將在第一次使用時完成(例如,首次調用函數時)。

當然,如你展示,你可以使用緊挨着的evalutated關閉,以便有一個多行的初始化表達式:

enum Constants { 
    static let c: [Character] = { 
     // ... 
     return Array("abc".characters) 
    }() 
    // ... 
} 
+0

太棒了,所以它在Swift中執行靜態是枚舉靜態的。傑出,謝謝。來自位碼的決定性信息,謝謝。 – Fattie

1

我想你應該假設ck是每次計算。計算可能會作爲編譯器的實現細節進行優化,但如果我是你,我不會指望這一點。

Swift沒有等價於局部變量(即函數內的「自動」變量,其值在函數調用之間維持)。

如果你真的想努力確保k只計算一次,使其成爲一個真正的常數(即在課堂上)。當然,您還需要爲c做同樣的事情,因爲您在以後的計算中需要它。這似乎是在這種情況下,一個愚蠢的例子,但我經常這樣做時所創建的事情是重量級的,好像是會反覆使用的圖像或視圖:

class MyView : UIView { 
    lazy var arrow : UIImage = self.arrowImage() 
    func arrowImage() -> UIImage { 
     // ... big image-generating code goes here ... 
    } 
} 

我一遍又一遍地呼喚arrowImage()直到我對自己說,等等,我可以使這個常量(這裏表示爲lazy var)並且只計算一次,即第一次訪問arrow

+0

我明白了,所以「懶VAR」是在解決方案類級別('lazy var c = Array(「abc」.characters)',這很簡單);不能在一個函數中做。非常感謝。 – Fattie