Swift 样式循环的多个增量

Multiple increments in Swift style for loops

我的 Swift 代码中有以下循环:

for var i:Int = 0, j:Int = 0; i < rawDataOut.count; i += 4, ++j {
    maskPixels[j] = rawDataOut[i + 3]
}

我在 Xcode 中收到两个警告:

  1. C 风格的 for 语句已弃用,将在 Swift
  2. 的未来版本中删除
  3. '++' 已弃用:它将在 Swift 3
  4. 中删除

我看不出如何在 Swift 的 For In Loops 中重写它以考虑到两个变量和 4 步而不会变得混乱。有没有简单优雅的翻译?

回答这个问题的先决条件:查看你的例子

我假设您打算将 i 限制为 i < rawDataOut.count-3 而不是 i < rawDataOut.count,否则按索引访问 rawDataOut[i + 3] 元素没有多大意义 w.r.t。运行时安全。无论如何,如果您不向我们展示 rawDataOut,这是我们必须做出的假设。

因此,您的原始循环(包括可验证的示例)如下所示

/* example data */
var rawDataOut = Array(1...40)
var maskPixels = [Int](count: 10, repeatedValue: 0)

/* your pre-Swift 2.2/3.0 loop */
for var i: Int = 0, j: Int = 0; i < rawDataOut.count-3; i += 4, ++j {
    maskPixels[j] = rawDataOut[i + 3]
}

print(maskPixels) //[4, 8, 12, 16, 20, 24, 28, 32, 36, 40]

使用for in ... where

在您的具体示例中,多个增量有一个简单的关系 (j=4*i),因此我们甚至可以在不使用显式 j 迭代的情况下解决这个问题,例如

/* example data */
var rawDataOut = Array(1...40)
var maskPixels = [Int](count: 10, repeatedValue: 0)

/* your pre-Swift 2.2/3.0 loop */
for i in 0..<(rawDataOut.count-3) where i%4 == 0 {
    maskPixels[i/4] = rawDataOut[i + 3]
}

print(maskPixels) // [4, 8, 12, 16, 20, 24, 28, 32, 36, 40]

但这对于两次迭代的一般性讨论可能并不真正感兴趣。我们继续使用结合 strideenumerate.

的 2 次迭代方法

合并 strideenumerate

一种解决方案是在上面的循环中枚举迭代i描述的stride,并使用枚举索引构造第二个迭代(上面的j)。在您的示例中,enumerate 索引完全对应于 j,即

/* example data */
var rawDataOut = Array(1...40)
var maskPixels = [Int](count: 10, repeatedValue: 0)

/* Swift >= 2.2 loop */
for (j, i) in 0.stride(to: rawDataOut.count-3, by: 4).enumerate() {
    maskPixels[j] = rawDataOut[i + 3]
}

print(maskPixels) // [4, 8, 12, 16, 20, 24, 28, 32, 36, 40]

请注意,在 Swift 3(与 2.2 相比)中,stride(to:by:)stride(through:by:) 的默认实现似乎是协议 Strideable (as non-blueprinted extension methods) will be depracated, and that we're back to (as in Swift 1.2) using the global functions stride(from:to:by:) and stride(from:through:by:), see e.g. the current master branch of swift/stdlib/public/core/Stride.swift


更棘手的情况:诉诸 while

对于更棘手的情况,请将 Swift 2.2 循环中的签名设为

for var i: Int = 0, j: Int = 0; i < rawDataOut.count-3; i += 4, j += i { ... }

你可能最好简单地使用一个 while 循环,其中一个迭代与循环不变量相关联,并将一个尾随迭代作为自由变量;我想这是否被认为是凌乱的是一个品味问题。

var i = 0, j = 0
while i < rawDataOut.count-3 {

    // ...

    // increase iterates
    i += 4
    j += i
}

我假设删除 C 风格循环的原因是,在大多数情况下,它直接被 for instride 等覆盖,并且对于这些还不够的情况,一个很好的老人' while,很可能会。

在Swift 4

for index in stride(from: 0, to: 10, by: 2){
    print(index)
}