Swift 3.0 で C言語スタイルの for ループが廃止されるので、その書き換え方法のまとめ

  • 132
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

C言語スタイル for ループの廃止

Screen Shot 2016-04-08 at 11.55.56 AM.png

C言語スタイルの for ループが Swift 3.0 で廃止される見込みの為(エラーメッセージには将来のみたいな表現だけど)、これまでこのスタイルで書いてきた for ループを書き直さないといけなくなりました。そこで、典型的なパターンを書き直す方法をまとめてみました。

for var i = 0 ; i < 100 ; i++

もっとも典型的な C言語スタイルの for ループ、0 から 100 未満の for ループの場合です。

// C-Style for statement
for var i = 0 ; i < 100 ; i++ {
    print("\(i)")
}
// Swift 3.0 ready
(0 ..< 100).forEach { print("\($0)") }
// Swift 3.0 ready
for i in (0 ..< 100) {
    print("\(i)")
}

for var i = 99 ; i >= 0 ; i--

典型的な降順の場合です。

// C-Style for statement
for var i = 99 ; i >= 0 ; i-- {
    print("\(i)")
}

reverse() を使います。

// Swift 3.0 ready
(0 ..< 100).reverse().forEach { print("\($0)") }
// Swift 3.0 ready
for i in (0 ..< 100).reverse() {
    print("\(i)")
}

for var i = 0 ; i < 100 ; i += 2

飛び石になる場合です。

// C-Style for statement
for var i = 0; i < 100 ; i += 2 {
    print("\(i)")
}

stride を使います。to の他に through もあります。

// Swift 3.0 ready
0.stride(to: 100, by: 2).forEach { print("\($0)") }

stride(to:by:)stride(through:by:) の違い

誤解しそうですが昇順の場合は、 to は「未満」、through は「以下」を意味するようです。以下の例を参考にしてください。

0.stride(to: 20, by: 5) // 0, 5, 10, 15
0.stride(through: 20, by: 5) // 0, 5, 10, 15, 20

for var i = 98 ; i >= 0 ; i -= 2

飛び石で降順の場合です。

// C-Style for statement
for var i = 98 ; i >= 0 ; i -= 2 {
    print("\(i)")
}
// Swift 3.0 ready
98.stride(through: 0, by: -2).forEach { print("\($0)") }

こんな書き方もありですね。EDIT¹

// Swift 3.0 ready
0.stride(to: 100, by: 2).reverse().forEach { print("\($0)") }
// Swift 3.0 ready
for i in 0.stride(to: 100, by: 2).reverse() {
    print("\(i)")
}

EDIT¹: 昇順だと 0.stride(to: 100, by: 2) とかの表現が、降順だと ストレートに表現できず、解釈の入ったようなコードにならざるをえないような気がします。良さそうなアイディアがあればコメントくだされば幸いです。

次の再初期化式の指定がなく、刻みが不定の場合

あまり良い例が思いつきませんが、例えば二乗した値が奇数か偶数かで、加算する値が変わる場合を例にしてみます。(例自体には深い意味はありません)

// C-Style for statement
for var i = 0 ; i < 100 ; {
    print("\(i)")
    if (i * i) % 2 == 0 { i += 1 }
    else { i += 2 }
}

while ループに置き換えるのが良さそうです。

// Swift 3.0 ready
var i = 0
while i < 100 {
    print("\(i)")
    if (i * i) % 2 == 0 { i += 1 }
    else { i += 2 }
}

for ループから条件によって抜け出す場合がある場合

あまり良い例が思いつかないのですが、サイコロを振るように乱数を発生させて、特定の数が出たらループを終わらせる事にしてみましょう。

// C-Style for statement
for var i = 0 ; i < 100 ; i++ {
    print("\(i)")
    if arc4random_uniform(10) == 0 { break }
}

残念ながら、forEach {} では break 文で for ループを抜ける事は出来ません。そこで、 for-in 文を使います。

// error: forEach で break は使えない
(0 ..< 100).forEach {
    print("\(i)")
    if arc4random_uniform(10) == 0 { break } // error
}
// Swift 3.0 ready
for i in 0 ..< 100 {
    print("\(i)")
    if arc4random_uniform(10) == 0 { break } // OK
}

continue を使う場合も forEach は使えないので、同様に for-in に書き換える必要があります。

浮動小数点数 など 整数 でない場合 EDIT²

CGFloat や Double なども Strideable なので同様に書くことができます。

CGFloat(0).stride(to: 100, by: 1.5).forEach { print("\($0)") }
0.0.stride(to: 100.0, by: 1.5).forEach { print("\($0)") }

あとがき

EDIT¹: 例を追加しました。
EDIT²: 項目を追加しました。

Swift3.0の正式リリース時にはきっと、Apple は「素晴らしいCode のコンバージョンツールを用意する」的な発言をするかと思いますが、この変換を自動的に行えるとは正直思えません。そのかわり、次のバージョンでの変更点などが warning で表示されるのは、時間ができた時に少しづつ移行させる方法は大変合理的だと思います。

それではみなさん、Have a happy coding!!

Swift Version:
Apple Swift version 2.2 (swiftlang-703.0.18.1 clang-703.0.29)