【问题标题】:Is the for loop condition evaluated each loop in Swift?for 循环条件是否评估了 Swift 中的每个循环?
【发布时间】:2015-07-05 22:26:39
【问题描述】:

我在工作中有一个小小的争论:在运行它的项目之前快速计算数组的大小是一个好习惯吗?什么是更好的代码实践:

选项 A:

    func setAllToFalse() {
        for (var i = 0; i < mKeyboardTypesArray.count; i++ ) {
            self.mKeyboardTypesArray[i] = false
        }
    }

选项 B:

    func setAllToFalse() {
        let typesCount = mKeyboardTypesArray.count
        for (var i = 0; i < typesCount; i++ ) {
            self.mKeyboardTypesArray[i] = false
        }
    }

当然,如果我在循环期间不更改数组的话。

我确实查看了文档,其中指出:

循环执行如下:

第一次进入循环时,初始化表达式为 评估一次,以设置所需的任何常量或变量 为循环。评估条件表达式。如果它评估 为false,循环结束,for之后代码继续执行 循环的右大括号 (})。如果表达式的计算结果为真,则代码 通过执行大括号内的语句继续执行。 执行完所有语句后,增量表达式为 评估。它可能会增加或减少计数器的值,或者 根据 陈述的结果。增量表达式之后 求值,执行返回到第 2 步,条件表达式 再次评估。

【问题讨论】:

  • 我认为你要么必须研究生成的汇编代码,要么等到 Swift 开源。 Swift 编译器应该非常非常非常聪明,有很多优化。此外,如果您确定数组不会改变,您可以使用:for val in array { ... },这肯定是最快的方法。
  • @Kametrixom,你是对的。但是你不能使用上面示例中的 for.. in 语法,因为你得到的 val 实际上是一个 let 变量,它不能改变,所以你必须使用更长的语法。
  • 您可以使用for var val in array { ... } ;)。但我知道你的意思,你可以使用for i in 0..&lt;array.count { ... },它绝对不会每次都调用.count
  • 但我完全忘记了 0..
  • 是的,我真的很喜欢 Swift 有很多不同的 for 循环语法(es?)

标签: swift for-loop


【解决方案1】:

在 Swift 中的惯用方式是:

func setAllToFalse() {
    mKeyboardTypesArray = mKeyboardTypesArray.map {_ in false}
}

这样,没有什么可以评估,也没有什么可以计算。

事实上,这会是一个不错的 Array 方法:

extension Array {
    mutating func setAllTo(newValue:T) {
        self = self.map {_ in newValue}
    }
}

现在你可以说:

mKeyboardTypesArray.setAllTo(false)

或者,您也可以这样做(这涉及使用count,但只能使用一次):

mKeyboardTypesArray = Array(count:mKeyboardTypesArray.count, repeatedValue:false)

【讨论】:

  • 并没有真正回答这个问题,但我一般倾向于更多地使用函数式编程,它可以使 de 看起来更好,并消除很多潜在的错误
  • 我不想开始争论,但我认为他的意思是 Option AOption B
  • 这些是 C 风格的 for 循环。这不是好的 Swift 风格。这就是我的回答。如果你有不同的答案,请给出你的答案。让群众决定。请不要一直用 cmets 唠叨我。谢谢。
【解决方案2】:

每次循环都会评估循环条件。考虑这个实验:

extension Array {
    var myCount: Int {
        get {
            println("here")
            return self.count
        }
    }
}

let a = [1, 2, 3, 4, 5]

for var i = 0; i < a.myCount; i++ {
    println(a[i])
}

输出:

这里
1
这里
2
这里
3
这里
4
这里
5
这里

您可以从 选项 B 中看到速度的小幅提升,但我希望 Array 上的 count 属性在数组不变的情况下不会很昂贵。无论如何,这可能是一种很好的代码实践,因为它向读者传达了您希望数组大小在循环期间保持不变。

编译器可能会通过检测循环中没有任何内容修改数组来优化array.count,但由于println 的副作用,它无法对array.myCount 执行此操作。

【讨论】:

  • 我认为整个问题都围绕着优化器是否可以优化掉“array.count”调用。与调用具有特殊副作用的方法无关。
【解决方案3】:

我发现它不是,如果您正在遍历数组并删除项目(例如),这可能会导致崩溃。在当前的 Swift 语法中,这个 for 循环

        for i in 0..<m_pendingCommands.count
        {
            if m_pendingCommands[i].packetID < command.packetID
            {
                m_pendingCommands.remove(at: i)
            }
        }

在数组中途崩溃,索引错误。

我将其切换为 while 循环:

    var i: Int = 0
    while i < m_pendingCommands.count
    {
        if m_pendingCommands[i].packetID < ID
        {
            m_pendingCommands.remove(at: i)
        }
        else
        {
            i += 1
        }
    }

【讨论】:

    猜你喜欢
    • 2013-03-23
    • 2011-12-17
    • 1970-01-01
    • 2010-11-17
    • 1970-01-01
    • 1970-01-01
    • 2010-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多