计数器作为for-in-loops中的变量
Counter as variable in for-in-loops
当通常使用 for-in-loop 时,计数器(在本例中 number
)在每次迭代中都是一个常量:
for number in 1...10 {
// do something
}
这意味着我无法在循环中更改 number
:
for number in 1...10 {
if number == 5 {
++number
}
}
// doesn't compile, since the prefix operator '++' can't be performed on the constant 'number'
有没有办法将 number
声明为变量,而无需在循环之前声明它,或者使用普通的 for 循环(带初始化、条件和增量)?
答案是 "no",这是一件好事。否则,可能会出现像这样非常混乱的行为:
for number in 1...10 {
if number == 5 {
// This does not work
number = 5000
}
println(number)
}
想象一下,有人在循环输出中看到数字 5000 时感到困惑,该循环理应绑定到 1 到 10(含)的范围。
此外,Swift 会选择什么作为下一个值 5000?它应该停止吗?它是否应该在分配之前继续到范围内的下一个数字?它应该在超出范围的赋值时抛出异常吗?这三个选择对他们来说都有一定的有效性,所以没有明确的赢家。
为了避免这种情况,Swift 设计者将范围循环中的循环变量设为不可变。
要理解为什么 i
不能可变,需要知道 for…in
是什么 shorthand。 for i in 0..<10
由编译器扩展为以下内容:
var g = (0..<10).generate()
while let i = g.next() {
// use i
}
每次循环,i
都是一个新声明的变量,解包的值是在生成器上调用 next
的下一个结果。
现在,while
可以这样写:
while var i = g.next() {
// here you _can_ increment i:
if i == 5 { ++i }
}
但当然,这无济于事——g.next()
下次循环时仍会生成 5。 body 中的增量毫无意义。
大概是因为这个原因,for…in
不支持相同的 var
语法来声明它的循环计数器——如果您不了解它是如何工作的,将会非常混乱。
(与 where
不同,在这里您可以看到正在发生的事情 – var
功能偶尔有用,类似于 func f(var i)
的功能)。
如果你想要跳过循环的某些迭代,你最好的选择(不求助于 C-style for
或 while
)是使用一个生成器来跳过循环相关值:
// iterate over every other integer
for i in 0.stride(to: 10, by: 2) { print(i) }
// skip a specific number
for i in (0..<10).filter({ [=12=] != 5 }) { print(i) }
let a = ["one","two","three","four"]
// ok so this one’s a bit convoluted...
let everyOther = a.enumerate().filter { [=12=].0 % 2 == 0 }.map { [=12=].1 }.lazy
for s in everyOther {
print(s)
}
更新Swift 5
for var i in 0...10 {
print(i)
i+=1
}
当通常使用 for-in-loop 时,计数器(在本例中 number
)在每次迭代中都是一个常量:
for number in 1...10 {
// do something
}
这意味着我无法在循环中更改 number
:
for number in 1...10 {
if number == 5 {
++number
}
}
// doesn't compile, since the prefix operator '++' can't be performed on the constant 'number'
有没有办法将 number
声明为变量,而无需在循环之前声明它,或者使用普通的 for 循环(带初始化、条件和增量)?
答案是 "no",这是一件好事。否则,可能会出现像这样非常混乱的行为:
for number in 1...10 {
if number == 5 {
// This does not work
number = 5000
}
println(number)
}
想象一下,有人在循环输出中看到数字 5000 时感到困惑,该循环理应绑定到 1 到 10(含)的范围。
此外,Swift 会选择什么作为下一个值 5000?它应该停止吗?它是否应该在分配之前继续到范围内的下一个数字?它应该在超出范围的赋值时抛出异常吗?这三个选择对他们来说都有一定的有效性,所以没有明确的赢家。
为了避免这种情况,Swift 设计者将范围循环中的循环变量设为不可变。
要理解为什么 i
不能可变,需要知道 for…in
是什么 shorthand。 for i in 0..<10
由编译器扩展为以下内容:
var g = (0..<10).generate()
while let i = g.next() {
// use i
}
每次循环,i
都是一个新声明的变量,解包的值是在生成器上调用 next
的下一个结果。
现在,while
可以这样写:
while var i = g.next() {
// here you _can_ increment i:
if i == 5 { ++i }
}
但当然,这无济于事——g.next()
下次循环时仍会生成 5。 body 中的增量毫无意义。
大概是因为这个原因,for…in
不支持相同的 var
语法来声明它的循环计数器——如果您不了解它是如何工作的,将会非常混乱。
(与 where
不同,在这里您可以看到正在发生的事情 – var
功能偶尔有用,类似于 func f(var i)
的功能)。
如果你想要跳过循环的某些迭代,你最好的选择(不求助于 C-style for
或 while
)是使用一个生成器来跳过循环相关值:
// iterate over every other integer
for i in 0.stride(to: 10, by: 2) { print(i) }
// skip a specific number
for i in (0..<10).filter({ [=12=] != 5 }) { print(i) }
let a = ["one","two","three","four"]
// ok so this one’s a bit convoluted...
let everyOther = a.enumerate().filter { [=12=].0 % 2 == 0 }.map { [=12=].1 }.lazy
for s in everyOther {
print(s)
}
更新Swift 5
for var i in 0...10 {
print(i)
i+=1
}