繁体   English   中英

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

[英]Swift constants (with a calculation) in functions?

这是一个简单的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 )如果上述问题的答案是“否,则每次调用test时都会计算c和'k'”,那么在那种情况下,如何在函数内放置一种静态计算属性?

不,在您的特定情况下,编译器当前不会将c和/或k优化为仅求值一次的常量表达式(这可以通过在优化的构建中检查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的初始化程序表达式都将只被评估一次,这将在首次使用它们时(即,在首次调用该函数时)进行。

当然,正如您所展示的,您可以使用立即评估的闭包以具有多行初始化表达式:

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

我认为您应该假设每次都计算ck 可能会将计算优化为编译器的实现细节,但是如果您是我,我不会指望这一点。

Swift没有等效于C static局部变量(即,函数内的“自动”变量,其值在两次调用之间保持不变)。

如果您真的想确保k仅计算一次,请使其为真正的常量(即在类级别)。 当然,您还需要对c进行相同的操作,这在以后的计算中需要。 在这种情况下,这似乎是一个愚蠢的示例,但是当创建的东西很重时,例如在反复使用的图像或视图时,我经常这样做:

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

arrowImage()调用arrowImage() ,直到我对自己说,等等,我可以将其设为一个常数(在这里表示为lazy var )并仅对其进行一次计算,即第一次访问arrow

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM