Swift3.0以降のfor文に対応する


ご存知の方も多いと思いますが、Swift3.0からいわゆるC言語スタイルのforループ文が廃止されます。
Remove C-style for-loops with conditions and incrementers

C言語スタイルというのは次のような構文ですね。
プログラマなら馴染みがありすぎるのではないでしょうか。

for var i = 0; i < 10; i++ {
    print(i)
}

ちなみにSwift3.0ではインクリメント演算子++、デクリメント演算子- -も廃止されることにも注意です。
脈々と受け継がれてきたこの書き方が廃止されること、そしてそのディシジョンを下すSwiftチームの思いきりに驚きます。

廃止される以上書き換えが必要になりますが、書き換えの方法は二つあります。

  1. for..in..を用いる
  2. 関数型言語的に書く

二つ目がわかりづらい書き方していますが、要は便利な関数が標準ライブラリに用意されているのでそれを使おうぜという話です。
こちらはクロージャが活躍するので、Swiftのクロージャの記法に慣れてない人はそちらも確認しておきましょう。

では各場合における書き換えを見ていきます。

インクリメント

最もシンプルな場合ですね。

for var i = 0; i < 10; i++ {
    print(i)
}

次のように変更します。

//for inを使う
for i in 0 ..< 10 {
    print(i)
}

//関数forEachを使う
(0 ..< 10).forEach { (num) in
    print(num)
}

//短縮形
(0 ..< 10).forEach { print($0) }

最後のをクロージャ表記に慣れてない方に補足しておくと、
Swiftではクロージャの引数に自動的に$0、$1、$2…と順に名前が付与されます。
今回の例では$0が非短縮の場合のnumにあたります。
 

デクリメント

for var i = 9; i >= 0; i-- {
    print(i)
}

デクリメントの場合は関数reverseを用いてあげます。

for i in (0..<10).reverse() {
    print(i)
}

(0..<10).reverse().forEach{ print($0) }

 

1以外の刻み

for var i = 0; i < 10; i += 2 {
    print(i)
}

1以外の刻みで数字を増減させたい時はstrideを用います。

for i in 0.stride(to: 10, by: 2) {
    print(i)
}

0.stride(to: 10, by: 2).forEach{ print($0) }

//最後も含める場合はtoをthroughに変える
0.stride(through: 10, by: 2).forEach{ print($0) }

 

条件指定(if文ネスト)

for文の中でif文がネストするというのもよくあるパターンですね。

for var i = 0; i < 10; i++ {
    if i % 2 == 0 {
        print(i)
    }
}

次のように書き換えられます。

//whereで条件指定ができる
for i in 0 ..< 10 where i % 2 == 0 {
    print(i)
}

//filterは条件に合致する要素を取り出した配列を返す
(0 ..< 10).filter{ $0 % 2 == 0 }.forEach{ print($0) }

補足すると、二つ目はクロージャのreturnを省略した書き方です。

 

配列を扱う

配列に対してループを回す場合です。

let array = ["Alice", "Bob", "David"]
for var i = 0; i < array.count; i++ {
    print(array[i])
}

配列Arrayも範囲Rangeと同様の書き換えができます。

for element in array {
    print(element)
}

array.forEach { print($0) }

 

配列のインデックスを使う

let array = ["Alice", "Bob", "David"]
for var i = 0; i < array.count; i++ {
    print("\(i+1)番目の名前は\(array[i])")
}

enumulateを用います。

//enumulateでインデックスと要素のタプルを扱えるようにする
for (index,element) in array.enumerate() {
    print("\(index + 1)番目の名前は\(element)")
}

array.enumerate().forEach { print("\($0.0 + 1)番目の名前は\($0.1)") }

$0.0、$0.1はタプル$0の各要素にアクセスしており、つまりそれぞれindexとelementにあたります。

 

辞書型を扱う

Cスタイルからの書き換えではないですが、せっかくなので辞書型のループも合わせて載せておきます。

let dictionary = ["name" : "Alice" , "hobby": "sport"]
for (key,value) in dictionary {
    print("key: \(key), value: \(value)")
}

dictionary.forEach { print("key: \($0.0), value: \($0.1)") }

 
 

慣れ親しんだfor文が廃止と聞くと驚きますが、言語側でお膳立てがしっかりしているので
対応はそれほど難しいところはないのではないでしょうか。
関数的な処理は見た目から慣れは要りますが、とてもスマートに書けるので積極的に使いたいですね。

for..in..と関数のどちらか自分が書きやすい方で書くことになりますが、
チーム開発であればコーディング規約を設けるのも大切になると思います。

  • このエントリーをはてなブックマークに追加

PAGE TOP