for制御構文

繰り返し構文で代表的なもののひとつがfor制御構文だ。多くのプログラミング言語で提供されており、PowerShell Coreにも用意されている。for制御構文でできることはwhile制御構文でできることとほとんど同じ。for制御構文とwhile制御構文は書き方が違うといった捉え方をしておくと良いかも知れない。

while制御構文では、事前に条件判定用の変数を設定し、while制御構文のブロックの最後で条件判断用変数をインクリメントするといった処理を行う。for制御構文はこのwhile制御構文の決まりきった書き方をまとめて書けるようにしたもので、for()の状態でこの繰り返し処理がどのようなものであるかを理解できるようになるという特徴がある。

for制御構文の書き方

for制御構文は基本的に次のような書き方をする。

for制御構文の書き方

for (初期設定; 条件; 繰り返し実行) {
    処理
}

PowerShell Coreの場合は次のようにセミコロンを利用する代わりに改行させるといった書き方をすることもできる。

セミコロンを使わないで書いた場合

for (初期設定
     条件
     繰り返し実行) {
    処理
}

for制御構文がどのようなものかは、for制御構文をwhile制御構文で書き換えてみるとわかりやすい。次のようにwhile制御構文を記述すると、for制御構文を使った場合と処理が同じということになる。

for制御構文をwhile制御構文で書き換えた場合

初期設定
while (条件) {
    処理

    繰り返し実行
}

条件で指定できる演算子はif制御構文やwhile制御構文で使ったものと同じだ。次のようにハイフンからはじまる演算子を指定するというシェルのtestコマンドのような作りになっている。

演算子 内容
-eq 等価
-ne 等価ではない
-gt よりも大きい 
-ge よりも大きいまたは等しい
-lt よりは少ない
-le よりは少ないまたは等しい
-like ワイルドカードパターンに一致する
-notlike ワイルドカードパターンに一致しない
-match 正規表現パターンに一致する
-notmatch 正規表現パターンに一致しない
-contains 参照値がコレクションに含まれている
-notcontains 参照値がコレクションに含まれていない
-in テスト値がコレクションに含まれている
-notin テスト値がコレクションに含まれていない
-is 同じオブジェクト型である
-isnot 同じオブジェクト型ではない

ハイフンからはじまる演算子は馴れないと違和感を感じると思うが、たとえば-eqはequalだし、-gtはgreater than(よりも大きい)の頭文字だしと、馴れてくるとすらすらと書けるようになると思う。

for制御構文の実行例

for制御構文の使用例を見ながらこの機能の使い方を探っていこう。次のコードがfor制御構文のもっとも基本的な使い方といったところだ。

for制御構文のもっとも基本的な使い方

PS /Users/daichi> for ($i = 1; $i -lt 10; $i++) { Write-Host $i }
1
2
3
4
5
6
7
8
9
PS /Users/daichi>

まず変数$iに1を代入し、$iが10よりも小さい値である場合、ブロックの中の処理であるWrite-Host $iを実行する、といった内容になっている。ブロックの中の処理が終わると$i++が実行され、$iの値が1増えることになる。この繰り返しによって$iの値が1から9の間は繰り返し処理が実行され、$iの値が10になると条件を満たさなくなるためwhile制御構文は処理を終了する。

while制御構文で繰り返し処理から抜けるためのbreakと、次の繰り返しに飛ぶcontinueの2つの機能を紹介したが、これはfor制御構文でも利用することができる。たとえば次のようにして繰り返しの途中で繰り返しを終了するようにbreakを入れると、breakが実行された段階でfor制御構文が終了することを確認できる。

breakが実行された段階でfor制御構文は終了

PS /Users/daichi> for ($i = 1; $i -lt 10; $i++) {
>>     if ( $i -eq 6 ) {
>>         break
>>     }
>>     Write-Host $i
>> }
1
2
3
4
5
PS /Users/daichi>

今度はcontinueを使ってみよう。次のように書くと、$iを2で割ったときの余りが0であるとき、つまり偶数であるときにはcontinueが実行される。continueが実行されると次の繰り返しへ飛ぶため、そのあとのWrite-Host $iが実行されなくなる。つまり、$iの値が偶数のときはWrite-Host $iが実行されないということになり、奇数だけが表示される。

continueを使って奇数だけを出力させる処理

PS /Users/daichi> for ($i = 1; $i -lt 20; $i++) {
>>     if ( $i % 2 -eq 0 ) {
>>         continue
>>     }
>>     Write-Host $i
>> }
1
3
5
7
9
11
13
15
17
19
PS /Users/daichi>

for制御構文は条件式に何も指定しないと常に真値として繰り返しが実施される。つまりfor (;;)と書くと無限ループになる。for (;;)で無限ループを作っておいて、内部で終了の条件を満たしたらbreakで抜けるというのもfor制御構文のよくある使い方だ。

for (;;)で無限ループ。処理の中でbreakを実行してループを抜ける

PS /Users/daichi> $i = 1
PS /Users/daichi> for (;;) {
>>     Write-Host $i
>>     if ($i -eq 10) {
>>         break
>>     }
>>     $i++
>> }
1
2
3
4
5
6
7
8
9
10
PS /Users/daichi>

for制御構文の書き方はこんなところだろう。while制御構文を使うかfor制御構文を使うかは好みがわかれるところだ。読みやすければ基本的にどちらでも構わないのではないかと思うが、for制御構文で簡素に表現できるときはfor制御構文を使った方がよいかもしれない。for ()の部分を見るだけでどういった目的のループであるかを判断しやすくなるからだ。

参考資料