Swift3より前に書いたCスタイルのfor文
for 初期設定; 実行条件; インクリメント
をSwift3以降で
for i in 範囲
に変換するときにハマるパターンがあります。
入れ物がいくつかある。
左からいくつかは丸が入っている。
残りの入れ物に三角を入れる処理を行いたい。
丸が入っている最終の入れ物のindexをcurrentPosとし、
最後の入れ物のindexをendPosとする。
三角を入れる処理のfor文は、Cスタイルの書き方では
for var i = currentPos + 1; i<=endPos; i += 1 {
//ポジションiに三角を入れる処理
}
と書ける。
この書き方を範囲指定の書き方に置き換えると
for i in (currentPos + 1)...endPos {
//ポジションiに三角を入れる処理
}
となる。
ところが次のように初めから全ての入れ物に丸が入っていた場合、上の範囲指定の書き方ではうまくいかない。
この場合、範囲 (currentPos + 1)...endPos
は 5...4
となって実行時エラーになる。範囲の指定は...方式でも..<方式でも、右より左の方が大きいと実行時エラーで落ちる。
Cスタイルの書き方では初期設定と実行条件を与えれば、あとは自動でうまくやってくれますが、Swiftでは範囲の生成がうまく出来ないと実行時エラーになってしまうので注意。
対策は
stride(from: , through: , by: )
を使うことです。throughの値よりもfromの値の方が大きい場合でも、何も実行せずに次の命令に移るだけなのでCスタイルで書くのと同じノリでいけます。
例に上げたやり方だと初期値は1大きいだけなので
(currentPos + 1)..<(endPos + 1)
でも対応できます。
また、dropFirst()を使う方法もあります。
for i in (0...endPos).dropFirst(currentPos + 1) {
}
で可能です。(コメントで指摘してもらったやり方)
Cスタイルのfor文をナウい形に書き換える際は、注意しておきたい。