Swift类型检查在非常短的函数上需要太长时间

Nic*_*ari 17 type-inference swift

我已将Swift编译器标志设置-warn-long-function-bodies为90毫秒,以查看我的项目中的哪些函数编译时间过长(由于类型检查).

我有以下方法:

func someKey(_ sectionType: SectionType, row: Int) -> String {
    let suffix = row == 0 ? "top" : "content"
    return "\(sectionType)_\(suffix)"
}
Run Code Online (Sandbox Code Playgroud)

(SectionType是一个String支持的枚举)

如上所述,2017款MacBook Pro 需要96毫秒.我尝试的第一件事是绕过字符串插值而\(sectionType.rawValue)不是使用\(sectionType),但现在它给了我106毫秒.错误的举动......

接下来,我改变了:

let suffix = row == 0 ? "top" : "content"
Run Code Online (Sandbox Code Playgroud)

至:

let suffix = "top"
Run Code Online (Sandbox Code Playgroud)

警告消失了,因此三元运算符导致了问题.

我尝试了这个:

let suffix: String = { // Note the type annotation!
    if row == 0 {
        return "top"
    }
    return "content"
}()
Run Code Online (Sandbox Code Playgroud)

...但是现在关闭需要97毫秒(整个功能,101).

我甚至尝试过更明确的:

    let suffix: String = {
        if row == 0 {
            return String("top")
        } else {
            return String("content")
        }
    }()
Run Code Online (Sandbox Code Playgroud)

......我闭嘴:94ms; 功能:98ms.

这是怎么回事?

我的90毫秒限制是否太低?我知道(是吗?)字典文字的类型检查错误,但这看起来完全不同......?

我的环境是Xcode 8.3.2(8E2002),Swift: Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42)


可是等等!还有更多...

我试过这个函数体:

func someKey(_ sectionType: SectionType, row: Int) -> String {
    if row == 0 {
        return "\(sectionType.rawValue)_top"
    } else {
        return "\(sectionType.rawValue)_content"
    }
}
Run Code Online (Sandbox Code Playgroud)

......它需要97ms~112ms!?


附录:我将函数和枚举移植到一个干净的,最小的项目(单视图应用程序)设置相同的警告,但它不会发生.我确信整个项目正在以某种方式影响这一方法,但还不能确定如何...


附录2:我测试了我的函数的静态版本:使用固定后缀"top"而不管它的值是什么row(这需要不到90毫秒并且不会触发警告),添加了以下if块:

func someKey(_ sectionType: SectionType, row: Int) -> String {
    if row == 0 {
        print("zero")
    } else {
        print("non-zero")
    }

    let suffix: String = "top"
    return "\(sectionType)_\(suffix)"
}
Run Code Online (Sandbox Code Playgroud)

这让我回到了96~98毫秒!那么比较行到零时会出现问题吗?


解决方法:我一直在玩我的代码并以某种方式发现,如果我用语句替换ifswitch,问题就会消失:

func someKey(_ sectionType: SectionType, row: Int) -> String {
    let suffix: String = {
        switch row {
        case 0:
            return "top"
        default:
            return "content"
        }
    }()
    return "\(sectionType)_\(suffix)"
}
Run Code Online (Sandbox Code Playgroud)

(我不会回答我自己的问题,因为我不认为这是对实际情况的解释)

Sco*_*zie 5

我认为这是三元运算符。

我在 Xcode 11 (~93ms) 中得到了类似的结果,但编译时间减少到 ~23ms:

func someKey(_ sectionType: SectionType, row: Int) -> String {

    var suffix = "top"

    if row != 0 {
        suffix = "content"
    }

    return "\(sectionType)_\(suffix)"
}
Run Code Online (Sandbox Code Playgroud)

通过改变这一行的逻辑,我想我们可以证明它是三元逻辑,因为该方法减少到~1ms。我刚刚将 row 设为布尔值。

func someKey(_ sectionType: SectionType, row: Bool) -> String {
    let suffix = row ? "top" : "content"
    return "\(sectionType)_\(suffix)"
}
Run Code Online (Sandbox Code Playgroud)

同样(没有双关语意)改变三元逻辑以let suffix = row != 0 ? "top" : "content"将编译时间减半。这与我的第一个代码块相当。!=Swift 比==.